.NET 中 Getter 和 Setter 的声明

170

我在想这些getter和setter声明之间的区别是什么,是否有一种首选的方法(以及为什么)。第一个可以通过Visual Studio自动生成。其他方法怎样呢?谢谢。

1st

string _myProperty { get; set; }

第二

string _myProperty;

public string myProperty
{
    get { return _myProperty; }
    set { _myProperty = value; }
}

第三

string _myProperty;

public string getMyProperty()
{
  return this._myProperty;
}

public void setMyProperty(string value)
{
  this._myProperty = value;
}

16
@Steve,这不是那个问题的重复,因为那个问题问的是“为什么”,而这个问题问的是“有什么区别”。一旦有人知道为什么要使用属性,下一个显然的问题就是“为什么有多种实现方法?” - Andrew Grothe
2
然后可能还有一些重复的内容:这里这里这里。对一个不可避免地会被问到多次的问题,在约5分钟内得到了9个答案 :P - anton.burger
3
这个主题的所有问题要么被标记为重复,要么属于不同的主题。原来的问题在哪里? - Argeman
8个回答

231

属性用于封装一些数据。您可以使用普通字段:

public string MyField

但是这个字段可以被类的所有外部用户访问。人们可以插入非法值或以你没有预料到的方式更改该值。

通过使用属性,您可以封装数据访问的方式。 C#有一个很好的语法,可以将字段转换为属性:

string MyProperty { get; set; }

这被称为自动实现属性。在需要的时候,可以将属性扩展为:

string _myProperty;

public string MyProperty
{
    get { return _myProperty; }
    set { _myProperty = value; }
}

现在您可以添加验证 setter 中的值的代码:

set
{
    if (string.IsNullOrWhiteSpace(value))
        throw new ArgumentNullException();

    _myProperty = value;
}

属性还可以为getter和setter使用不同的访问器:

public string MyProperty { get; private set; }

通过这种方式,您可以创建一个属性,任何人都可以读取该属性,但只能由类本身进行修改。

您还可以为您的getter添加完全自定义的实现:

public string MyProperty
{
    get
    {
        return DateTime.Now.Second.ToString();
    }
}

C#编译自动属性时,会生成中间语言(IL)。在IL中,你会看到一个get_MyProperty和一个set_MyProperty方法。它还会创建一个名为<MyProperty>k_BackingField的后备字段(通常这在C#中是非法命名,但在IL中却是合法的,这样可以避免生成的类型与你自己代码之间的冲突)。然而,在C#中,你应该使用官方属性语法。这样可以使C#使用起来更加愉悦(例如,在 IntelliSense 中)。

按照惯例,不应该使用属性进行耗时较长的操作。


3
只是为了明确,get_MyPropertyset_MyProperty方法将适用于任何具有getter和/或setter(分别)的属性,无论它是否是自动属性。自动属性之间唯一的区别在于自动生成的(并且在代码中不可访问的)后备字段。 - Adam Robinson

15

首先和其次的方法最终都会生成类似第三种方法的东西。不过,当您有属性的语法时,请勿使用第三种方法。

最后,如果您在getset中没有任何工作要做,则请使用第一种方法。

最终,第一和第二种方法只是某种形式的语法糖,但为什么要编写比必要更多的代码呢。

// more code == more bugs

仅为了好玩,想一想:

public string A { get; private set; }

现在这就简单多了不是吗?getset隐含public修饰符,但它们可以被覆盖。当定义属性本身时使用任何修饰符时,都将遵循同样的规则。


3
如果您将所有内容注释掉,那么就不会有任何错误!问题解决了。另外,为了澄清:第二个代码块(以及第三个代码块,但我们不使用它)允许您在实际获取变量值之前执行一些操作。例如,您可以设置一个标志:isAccessed = true; - Russell Uhl
1
@RussellUhl,是的,那是真的。这正是我为什么说“如果在getset中没有工作要做,那么使用第一个”的原因。 - Mike Perrenoud
2
@RussellUhl:我认为“代码行数越多,错误就越多”的假设是建立在你可以用更少的代码实现目标的前提下的。如果你可以注释掉整个程序但仍能实现你的目标,那么这样做可能是个好主意 ;) - Adam Robinson
1
@AdamRobinson,我遇到一些需要维护的程序,希望能够注释掉每一行代码。但我不认为这样会影响性能。 :D - Mike Perrenoud
@TheSolution 我之所以扩展它,是因为我觉得你处理得太快了。冷静点。 - Russell Uhl

14

使用此方法,您可以在getset代码块中执行某些代码。

private string _myProperty;
public string myProperty
{
    get { return _myProperty; }
    set { _myProperty = value; }
}

你也可以使用自动属性:

public string myProperty
{
    get;
    set;
}

.Net Framework将为您管理。它的创建是因为这是一种良好的实践,并使其易于完成。

您也可以控制这些作用域的可见性,例如:

public string myProperty
{
    get;
    private set;
}

public string myProperty2
{
    get;
    protected set;
}

public string myProperty3
{
    get; 
}

更新

现在在C#中,您可以初始化属性的值。例如:

public int Property { get; set; } = 1;

如果也可以定义它并将其设为只读,而无需设置。

public int Property { get; } = 1;

最后,您可以定义箭头函数。

public int Property => GetValue();

9

1号

string _myProperty { get; set; }

这在.NET世界中被称为自动属性。它只是#2的语法糖。
第二个。
string _myProperty;

public string myProperty
{
    get { return _myProperty; }
    set { _myProperty = value; }
}

这是通常的做法,如果您需要在属性中进行任何验证或额外的代码,这是必需的。例如,在WPF中,如果您需要触发属性更改事件。如果不需要,请使用自动属性,它几乎是标准的。

3

string _myProperty;

public string getMyProperty()
{
    return this._myProperty;
}

public string setMyProperty(string value)
{
    this._myProperty = value;
}

这里的this关键字是多余的,完全不需要。这些只是获取和设置方法,而不是属性,就像Java的做法一样。

3
只是为了澄清,在您的第三个例子中,_myProperty实际上并不是一个属性。它是一个带有获取和设置方法的字段(正如已经提到的,获取和设置方法应该指定返回类型)。
在C#中,大多数情况下应避免使用第三种方法。您只有当要返回的类型是数组时才会真正使用它,或者如果获取方法做了很多工作而不仅仅是返回一个值,那么您才会使用它。后者并不是真正必要的,但是出于明确的目的,一个执行很多工作的属性获取方法是具有误导性的。

0

第一个是默认的,当没有特殊情况需要返回或写入时使用。 第二个和第三个基本上是一样的,只是第三个版本稍微扩展了一点。


0

让我们从3开始。那是行不通的。public getMyProperty()没有返回类型。

而1和2实际上是相同的东西。2是编译后1变成的样子。

所以1和2是相同的东西。使用2可以在您的模型中进行一些验证或缓存。

除此之外,它们变得相同。


0

第一种是“短”形式 - 当您不想在getter和setter中进行花哨操作时使用它。在此形式中,无法执行方法或类似的操作。

第二种和第三种形式几乎相同,尽管第二种形式压缩为一行。由于它看起来有些奇怪并且不符合C' Stylguides,因此不建议使用此形式。

如果我希望为我的getter / setter使用某些特殊功能,例如使用延迟构造等,则会使用第三种形式。


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