自动实现的getter和setter与公共领域


76

我看到很多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;
}

明确地说,当您需要对基础数据进行一些转换时,我理解了获取方法和设置方法的价值。但是在您只是传递值的情况下,它似乎是多余的。

Answers:


50

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

几年前,杰夫·阿特伍德(Jeff Atwood)处理了这个问题。他回顾性指出的最重要的一点是,从字段更改为属性是代码中的重大更改。任何消耗它的东西都必须重新编译才能与新的类接口一起使用,因此,如果控件之外的任何东西正在消耗您的类,则可能会遇到问题。


感谢您提供的链接,并说服我在现场/属性切换中实际上会中断。这对我来说很奇怪,因为无论如何语法都是一样的。
tclem

您可能会认为它可以编译成同一件事,但显然内部机制略有不同。
德克斯特

9
在C#中,具有get和set属性的对象将编译为一对方法,例如get_PropertyName()和set_PropertyName(type value)。C#中的属性语法只是语法糖。属性可以执行代码,因此将它们编译为与字段相同的代码没有任何意义。
杰森·杰克逊

9
在JIT编译确实优化的性质没有代码等同于一个场,所以没有理由不使用属性给出#3.0+ C中的简写语法
ERV沃尔特

31

稍后将其更改为以下内容也更加简单:

public int x { get; private set; }

11
我...甚至都不知道你能做到。
Merus

没错,这非常有帮助,不幸的是,您不能在界面中做到这一点
Georges

9

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


1
但是,这如何改变班级的契约?无论哪种方式,point.x = 1;并且point.x工作得很好。
Ajedi32 '17

2
@ Ajedi32从技术上讲它们不是同一份合同。如果将其从字段更改为属性(或将属性更改为字段),则必须重新编译访问该成员的所有内容。因为访问属性和字段时编译的IL不同。
约瑟夫·戴格

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

从一开始就使用属性可以避免这种情况,并且您可以随意调整基础实现,而无需破坏客户端代码。


3

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

3

由于自动实现的getter在属性和实际的私有存储变量中使用相同的名称。将来如何更改?我认为要说的是使用自动实现的字段而不是字段,以便将来在需要向getter和setter添加逻辑的情况下可以对其进行更改。

例如:

public string x { get; set; }

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

如何更改自动吸气剂设置程序...例如,对于设置程序,您仅允许设置有效的电话号码格式...如何更改代码,以便仅更改类?

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

private string _x;

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

这就是您要使其具有灵活性吗?


2

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


2

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


1

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



1

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

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

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


2
并非完全正确,如果您具有SomePropName {get; 私人集;},以及使用该对象初始然后集属性..
jhexp

0

您永远不会知道以后是否不需要数据转换。如果您隐藏自己的成员,则为此做好了准备。由于界面保持不变,因此您的班级用户不会注意到您是否添加翻译。


0

最大的不同是,即使您更改内部结构,仍然可以按原样维护getter和setter,在不损害API用户的情况下更改其内部逻辑。


0

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


0

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

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

0

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

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

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


-1

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

不,从技术上讲没有什么区别,并且当我这些天真的想共享对某个对象的访问权时,我有时会使其成为final最终对象,而不是添加getter。

设置者和获取者被“出售”的方式是,您可能需要知道某人正在获得价值或改变价值-这仅对基元有意义。

该规则中不包括诸如DAO,DTO和显示对象之类的属性包对象,因为它们不是“对象”一词真正的“ OO设计”含义中的对象。(您不会想到将消息传递给DAO,它只是一堆属性/值对)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.