{ get; set; } 和访问修饰符

9

我刚开始学习C#,在getter和setter简写方面有些困难。

据我了解,下面两种方法是等价的。这是正确的吗?

//Method 1
public string name { get; set; }

//Method 2
private string name
public string getName() { return name;}
public string setName(string newName) { this.name = newName; }

其次,如果我们希望getter/setter和实例变量具有不同的访问修饰符,该怎么办呢?下面的代码会报错,告诉我访问器必须比属性更严格,并且我不能为两个访问器指定修饰符。能否有人澄清一下?
private int maxTime { public get; public set; }

编辑:澄清一下,我没有具体的目标,只是想了解。我不明白这个速记符号是做什么用的。在其他语言中,我有私有实例变量并使用公共的getter和setter来管理这些实例变量。如果我自己编写方法,它允许这样做,但是不能使用此速记符号。为什么会这样?

编辑2:最后一个问题,以检查我的理解。以下两个代码片段都使用属性来管理maxTime变量。它们之间唯一的区别是样式。这个说法正确吗?

private int maxTime;
public int MaxTime{ get; set; }

vs

private int maxTime;

public int MaxTime
{
    get { return maxTime; }
    set { maxTime= value; }
}

2
为什么你想在私有变量上使用公共的getter/setter? - eddie_cat
1
不,这两种方法并不相同。请解释您想要做什么,而不仅仅是您最终得到的代码。 - CodeCaster
你不能使用 private int maxTime { public get; public set; } 作为属性的外部访问方式(注意,这不是变量!),因为外部访问级别比内部更加严格。你可以使用 public int maxTime { private get; set; } - 注意 set 不需要 public 修饰符。 - PaulF
最有限的范围优先,这一点在错误提示中已经明确表述并且相当直观。public 作为 get/set 级别是多余的;具有 protectedprivate setpublic 属性可能会很有用。在 C# 中有许多处理属性的方法,因此,仅说明您打算执行的操作,并不要陷入比较其他语言和功能等效性的泥潭,这样会得到更好的答案。 - Grant Thomas
你不需要关心隐藏实例变量的访问修饰符,因为它是无法访问的。实际上存在一个隐藏的实例变量只是一种实现细节。 - Ralf
5个回答

19

不要使用错误的private int maxTime { public get; public set; },而是可以编写一个属性来填充私有字段:

代替错误的private int maxTime { public get; public set; },您可以编写一个属性来填充一个私有字段:

private int maxTime;

public int MaxTime
{
    get { return maxTime; }
    set { maxTime = value; }
}

当您想在获取或设置maxTime的值时应用逻辑时,这很有用。否则,一个简单的速记属性就可以:

public int MaxTime { get; set; }

您可以创建一个具有公共getter但私有setter的属性,例如:

public int MaxTime { get; private set; }

这对于只读属性很有用,通常属性在类的构造函数中填充。

您甚至可以创建一个具有公共setter但私有getter的属性,尽管我无法想象出任何此种情景会有用。此外,编码标准声称这应该是一个方法而不是一个属性。 (点击此处阅读)

public int MaxTime { private get; set; }

你在编辑2中提出的问题的答案是否定的。

第一段代码从未更改私有整数maxTime,而第二段代码则更改了它。但是,如果在类内部只使用属性MaxTime,则它们在功能上是等效的。

更新:

自C# 6以来,您可以编写没有setter的速记属性:

public int MaxTime {get;}

这些属性只能在构造函数中初始化,或像这样硬编码:(这也是C# 6的新功能)

public int MaxTime {get;} = DateTime.Now;

这对于不可变的属性很有用(与只读属性不同,这种属性的值一旦初始化后,在托管类内部也无法更改。)


所以在您的第二个代码片段中,获取和设置都是公共的吗? - JShell
是的。除非在getter或setter中指定了更严格的访问修饰符,否则它们都将具有属性访问修饰符。 - Zohar Peled
那么属性和一组处理获取/设置的方法之间有什么区别呢?这只是语言上的差异吗? - JShell
方法和属性在编写代码时是不同的东西,但据我所知,getter和setter被编译为获取和设置底层字段的方法。 - Zohar Peled
我在问题中添加了最后一个澄清,如果您不介意的话。 - JShell

6
//Method 1
public string name { get; set; }

//Method 2
public string name
public string getName() { return name;}
public string setName(string newName) { this.name = newName; }

以上两种方法并不相等。
更准确的比较应该是这样的:
//Method 1
public string name { get; set; }

//Method 2
private string name; // this is private, not public.
public string Name // this is a property, not a method.
{
    get
    {
        return this.name;
    }
    set
    {
        this.name = value;
    }
}

如果你想玩一下访问修饰符,比如将get设置为public,而将set设置为private,那么你可以这样做:

public int maxTime { get; private set; }

关于自动实现属性和编译器背后的魔法,更多信息请参考。


所以,经过快速的谷歌搜索,我对属性有了一些了解。但是它们的目的是什么?它们与仅设置或获取字段的方法有何不同? - JShell
看起来比拥有一堆getX()和setX()方法更可爱。 - loli
那么从功能上来说,差别不大,对吗? - JShell
1
@Jesse:没错。C#/.NET已经很好地包含了对概念差异的本地支持。但从功能上来说,它们基本上是相同的,这就是为什么即使没有属性的本地支持,像Java这样的语言仍然能够使用方法支持属性概念的原因。 - sstan

3
public string name { get; set; }

你所拥有的是自动实现属性,它内部会有一个支持私有字段(和编译时get/set方法)
在C#代码中,这相当于:
private string _name;
public string name
{
    get { return _name; }
    set { _name = value; }
}

在编译时,get/set会被转换为方法调用,有点类似于你所拥有的。

对于:

private int maxTime { public get; public set; }

错误非常清楚,您不能比属性本身拥有更少限制性的访问修饰符。例如,如果您希望您的public属性具有publicget,但是如果您只想允许从类内部设置属性,则可以这样做:
public int maxTime { get; private set; }

您还应该查看:.Net命名约定,最好遵循这个约定,这样您的属性名称就可以以大写字母开头。

2
第一种方法只是C#语法糖,用于自动实现属性。当您编译它时,它会提供适当访问器的实现。
第二个示例不同。在这里,您有一个公共作用域字段(通常不允许使用,因为封装原则)和两个访问变量的方法。在语义使用上有微妙的差别;通常属性用于公开状态,而方法通常表示该方法具有一些计算,并且不仅仅返回或更改当前状态(再次强调,这是一种约定,而不是硬性规定)。方法通常采用VerbAction命名风格(public Thing GetAThing() { })。
自动生成的属性可以具有不同的访问修饰符,但必须只能使get或set比整体修饰符不可访问。
public int X { get; private set; } // OK
public int X { private get; set; } // OK
private int X { public get; public set; } // NOT OK

1
当你说方法通常使用动词动作命名风格时,获取某些东西是否更适合于属性? - JShell
是的,但有时方法也会返回一些东西。我采用的惯例是,属性获取只会在过程中简单地返回一些状态,而方法可能会返回某些计算量较大的结果。我同意这是一个灰色地带,需要根据惯例来处理。 - Matt

1
当您使用像Method 1(public string name { get; set; })中的属性时,编译器会自动生成一个私有后备字符串变量和公共getter和setter方法。
一般的想法是将字段设为私有,并仅通过公共getter/setter方法进行访问。因此,如果使用Method 2,则声明变量为私有。
我建议使用ILDASM查看生成的IL代码,这有助于了解底层发生的情况。
第二个错误就是编译器所说的。构造的可见性必须一致。

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