繁体   English   中英

自动实现的 getter 和 setter 与公共字段

[英]Auto-implemented getters and setters vs. public fields

我看到很多 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 的价值。 但在您只是传递值的情况下,它似乎不必要地冗长。

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

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

以后改成这样也简单多了:

public int x { get; private set; }

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

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

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.");
}

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

由于自动实现的 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;
        }
    }; 
}

这就是你所说的让它变得灵活吗?

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 ; 
}
}

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

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

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

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

亲切的问候

还值得注意的是,您不能将自动属性设置为只读,也不能内联初始化它们。 这些都是我希望在 .NET 的未来版本中看到的东西,但我相信您在 .NET 4.0 中两者都做不到。

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

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

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

最大的区别在于,如果您更改了内部结构,您仍然可以按原样维护 getter 和 setter,更改它们的内部逻辑而不会伤害 API 的用户。

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

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

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

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

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

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

  1. 属性是一个成员,它提供了一种灵活的机制来只读或只写
  2. 可以覆盖属性,但不能覆盖字段。

添加 getter 和 setter 使变量成为一个属性,就像在 Wpf/C# 中工作一样。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM