为什么我需要使用get和set方法?

13

我有一段代码:

public class MyClass
{
    private string _myProperty;

    public string MyProperty
    {
        get
        {
            return _myProperty;
        }

        set
        {
            _myProperty = value;
        }
    }
}

这里的重点是什么?我本可以将 _myProperty 字符串声明为公共,任何我的类对象都能够直接访问并获取或设置其值。

相反,我们将 _myProperty 设置为私有,并使用 get 和 set 来访问它们,使用类对象。

无论哪种情况,类对象都能够访问它们,结果始终相同。

那么为什么要使用这种方法?仅仅因为我可以在 setter 中实现一些约束条件吗?

除此之外,将成员变量设置为公开,会导致什么问题?在这个例子中,我可以将 _myProperty 公开,而不是通过将其设置为私有来限制仅在该类中使用,正如面向对象编程所建议的那样。

5个回答

18

不,结果并非总是相同的。

  • 尝试绑定到公共字段(或执行任何使用反射并期望属性的操作)
  • 尝试通过引用传递属性(不可行)
  • 尝试稍后决定您想要日志记录等,并发现当您将其更改为属性时,您会失去源和二进制兼容性。

请阅读我之前写的这篇文章……

请注意,从C# 2开始,代码可以更加简短:

public class MyClass
{
    public string MyProperty { get; set; }
}

C# 有二进制兼容性吗?它不是总是在 JIT 中绑定吗? - Daniel
1
@Dani:不会的 - IL 将包含对字段或属性的引用,使用不同的操作码等。基本上,从使用字段更改为使用属性(反之亦然)是加载字段或调用方法之间的区别。如果它们是相同的,我会感到震惊的 :) - Jon Skeet

1

字段_myProperty是实现细节,它告诉编译器您想要一些存储字符串引用的空间,并给它一个名称。get/set方法是对象属性的一部分,抽象了如何实现MyProperty属性。因此,如果您想更改字符串的存储/检索方式,第三方依赖项无需重新编译。

您还可以使用自动属性来为您完成此操作:

public string MyProperty {get; set;}

字段也是类元数据的一部分,就像属性一样。只有局部变量是对编译器的提示,表示您需要一些存储空间。 - Joey
我去掉了“just”这个词。字段是存储元数据和访问元数据,这使它们不够灵活,以便满足它们同时指定存储位置和访问方式的要求。 - Mark Cidade

1

如果您只声明变量为Public,那么它们实际上不是属性。许多使用反射的功能将无法正常运行,特别是数据绑定、序列化等。

偶尔我会懒惰并这样做,特别是在VB.Net v4之前的版本中工作时,因为没有自动属性,但我总是后悔并回来正确地编写属性。

如果您的类将由其他开发人员编写的代码使用,则使用属性尤为重要,因为他们可能会遇到由于未编写完整属性而导致的限制问题。


0

需要注意的是,尽管将字段包装在属性中对于类通常很有帮助,但对于结构来说往往是适得其反的。许多关于结构使用的建议限制都源于一种假设,即所有结构字段都将被包装在属性中。如果结构的语义规定:

  1. 它的状态完全由固定数量的参数定义,这些参数全部公开暴露以供读取。
  2. 这些参数可以自由地分配任何合法的值组合,这些值与它们各自的类型相匹配。
  3. 结构的默认实例被指定为将所有参数初始化为它们各自类型的默认值。

暴露字段将会暴露数据类型的“内部工作原理”,但这种暴露并不排除数据类型未来任何有意义的更改,这些更改在规范中已经被排除。所有存储在可修改位置的结构体的所有字段都始终暴露用于变异,即使唯一的变异方式是从一个实例到另一个实例的所有公共和私有字段的批量复制。如果结构体的语义要求代码能够创建一个具有任意组合值的定义参数的实例,而没有任何限制,则直接暴露结构体的字段不会允许单线程代码做任何它不能更慢地完成的事情。暴露字段将允许代码执行以下操作,否则它将无法执行:

  1. 更快地执行
  2. 更清晰地表达其意图
  3. 在多线程场景中具有定义的语义,否则语义将不明确
我真的看不出要求类型的使用者运行得更慢、写得笨拙,并且具有模糊的多线程语义的好处。

请注意,如果有一个政策反对具有突变“this”的属性的结构体,而不是封装所有结构体字段的政策,那么像这样的语句:

myListOfPoint[4].X = 5;

即使语言允许在只读结构上调用属性设置器(假设目的是为了诸如...等事情),该操作也将被拒绝。
myArraySegment[3] = 9;

这将被理解为访问数组,而 myArraySegment 持有一个引用。


0
正如你所说,属性的主要原因是验证。每个类都有这个责任来保护它们的成员,而_myProperty是MyClass的一个成员。在.Net中实现这个责任的方式是属性。在Java中,你需要定义两个方法:SetMyPropety和GetMyProperty。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接