80

我看到很多用于执行此操作的 C# 类的示例代码:

public class Point {
    public int x { get; set; }
    public int y { get; set; }
}

或者,在旧代码中,同样具有显式私有支持值且没有新的自动实现属性:

public class Point {
    private int _x;
    private int _y;

    public int x {
        get { return _x; }
        set { _x = value; }
    }

    public int y {
        get { return _y; }
        set { _y = value; }
    }
}

我的问题是为什么。执行上述操作与仅将这些成员设为公共字段(如下所示)之间是否有任何功能差异?

public class Point {
    public int x;
    public int y;
}

需要明确的是,当您需要对基础数据进行一些转换时,我理解 getter 和 setter 的价值。但是在您只是传递值的情况下,这似乎是不必要的冗长。

4

17 回答 17

53

我倾向于同意(这似乎是不必要的冗长),尽管这是我们团队尚未解决的问题,因此我们的编码标准仍然坚持所有类的详细属性。

杰夫阿特伍德几年前处理过这个问题。他回顾性指出的最重要的一点是,从字段更改为属性是代码中的重大更改。任何消耗它的东西都必须重新编译才能使用新的类接口,所以如果你无法控制的任何东西正在消耗你的类,你可能会遇到问题。

于 2008-09-21T17:29:26.907 回答
31

稍后将其更改为这样也更简单:

public int x { get; private set; }
于 2008-09-21T17:28:18.903 回答
10

它封装了这些成员的设置和访问。如果从现在开始,代码的开发人员需要在访问或设置成员时更改逻辑,则可以在不更改类合同的情况下完成。

于 2008-09-21T17:26:08.100 回答
8

这个想法是即使底层数据结构需要改变,类的公共接口也不必改变。

C# 有时可以以不同的方式处理属性和变量。例如,您不能将属性作为 ref 或 out 参数传递。因此,如果您出于某种原因需要更改数据结构并且您正在使用公共变量并且现在您需要使用属性,那么您的接口将不得不更改并且现在访问属性 x 的代码可能不再像它是变量时那样编译X:

Point pt = new Point();
if(Int32.TryParse(userInput, out pt.x))
{
     Console.WriteLine("x = {0}", pt.x);
     Console.WriteLine("x must be a public variable! Otherwise, this won't compile.");
}

从一开始就使用属性可以避免这种情况,您可以根据需要随意调整底层实现,而不会破坏客户端代码。

于 2008-09-21T17:42:05.877 回答
5

Setter 和 Getter 使您能够添加额外的抽象层,并且在纯 OOP 中,您应该始终通过对象提供给外部世界的接口来访问对象......

考虑一下这段代码,它将把你保存在 asp.net 中,如果没有 setter 和 getter 提供的抽象级别,这是不可能的:

class SomeControl
{

private string _SomeProperty  ;
public string SomeProperty 
{
  if ( _SomeProperty == null ) 
   return (string)Session [ "SomeProperty" ] ;
 else 
   return _SomeProperty ; 
}
}
于 2009-04-22T14:22:29.987 回答
5

由于自动实现的 getter 对属性和实际的私有存储变量采用相同的名称。以后怎么改?我认为要说的重点是使用自动实现而不是字段,以便将来如果您需要向 getter 和 setter 添加逻辑,则可以更改它。

例如:

public string x { get; set; }

例如,您已经多次使用 x 并且您不想破坏您的代码。

您如何更改自动获取器设置器...例如对于设置器,您只允许设置有效的电话号码格式...您如何更改代码以便只更改类?

我的想法是添加一个新的私有变量并添加相同的 x getter 和 setter。

private string _x;

public string x { 
    get {return _x}; 
    set {
        if (Datetime.TryParse(value)) {
            _x = value;
        }
    }; 
}

这就是你说的让它灵活的意思吗?

于 2009-09-08T01:42:19.117 回答
2

在绑定和序列化方面,还需要考虑更改对公共成员的影响。这两者通常都依赖公共属性来检索和设置值。

于 2008-09-21T17:50:42.050 回答
2

此外,您可以在 getter 和 setter 上设置断点,但不能在字段上设置断点。

于 2009-09-08T01:45:53.663 回答
1

AFAIK 生成的 CIL 接口不同。如果您将公共成员更改为属性,则您正在更改它的公共接口,并且需要重新构建使用该类的每个文件。如果您只更改 getter 和 setter 的实现,则不需要这样做。

于 2008-09-21T17:44:17.307 回答
1

也许只是公开领域,你可以引导你到一个更贫血的领域模型

亲切的问候

于 2008-09-21T17:55:23.473 回答
1

还值得注意的是,您不能将 Auto Properties 设为 Readonly,也不能内联初始化它们。这两个都是我希望在 .NET 的未来版本中看到的东西,但我相信你在 .NET 4.0 中都做不到。

这些天,我唯一一次使用带有属性的支持字段是当我的类实现 INotifyPropertyChanged 并且我需要在属性更改时触发 OnPropertyChanged 事件。

同样在这些情况下,我在从构造函数传入值时直接设置支持字段(无需尝试触发 OnPropertyChangedEvent(此时无论如何都会为 NULL),在我使用属性本身的其他任何地方。

于 2009-09-08T02:10:55.137 回答
0

您永远不知道以后是否需要对数据进行一些翻译。如果你隐藏你的成员,你就准备好了。如果您添加翻译,您班级的用户不会注意到,因为界面保持不变。

于 2008-09-21T17:26:41.093 回答
0

最大的区别是,如果你改变了你的内部结构,你仍然可以保持 getter 和 setter 的原样,改变它们的内部逻辑而不会伤害你的 API 的用户。

于 2008-09-21T17:27:14.540 回答
0

如果在这种情况下必须更改获取 x 和 y 的方式,则可以稍后添加属性。这是我觉得最令人困惑的地方。如果您使用公共成员变量,您可以稍后轻松地将其更改为属性,如果您需要在内部存储值,则可以使用名为 _x 和 _y 的私有变量。

于 2008-09-21T17:31:57.197 回答
0

原则上,setter 和 getter 是不好的(它们是一种糟糕的 OO 气味——我不会说它们是一种反模式,因为它们有时确实是必要的)。

不,从技术上讲没有区别,当我现在真的想共享对对象的访问时,我偶尔会将其设为 public final 而不是添加 getter。

setter 和 getter 被“出售”的方式是,您可能需要知道某人正在获取一个值或更改一个值 - 这仅对原语有意义。

属性包对象(如 DAO、DTO 和显示对象)被排除在此规则之外,因为这些不是对象一词的真正“OO 设计”含义中的对象。(您不会想到“向 DTO 或 bean 传递消息”——这些只是设计上的一堆属性/值对)。

于 2008-09-23T20:58:57.570 回答
0

为什么我们不只是使用公共字段而不是使用属性然后在我们不需要进行验证时调用访问器(get,set)?

  1. 属性是提供灵活机制以只读或只写的成员
  2. 可以覆盖属性,但不能覆盖字段。
于 2019-11-19T10:35:36.477 回答
0

添加 getter 和 setter 使变量成为在 Wpf/C# 中工作的属性。

如果它只是一个公共成员变量,则无法从 XAML 访问它,因为它不是属性(即使它的公共成员变量)。

如果它有 setter 和 getter,那么它可以从 XAML 访问,因为它现在是一个属性。

于 2020-01-18T03:21:16.830 回答