如果在C#自动属性中,get和set都是必需的,那么为什么我还要费心指定"get;set;"呢?
如果在C#自动属性中,get和set都是必需的,那么为什么我还要费心指定"get;set;"呢?
因为您可能需要一个只读属性:
public int Foo { get; private set; }
只写属性:
public int Foo { private get; set; }
错误:属性或索引器不能作为 out 或 ref 参数传递
如果你没有指定 {get; set;}
,那么编译器就不知道它是一个字段还是一个属性。
这很重要,因为虽然它们“看起来”相同,但编译器对它们的处理方式是不同的。例如,在属性上调用 "InitAnInt" 会引发错误。
class Test
{
public int n;
public int i { get; set; }
public void InitAnInt(out int p)
{
p = 100;
}
public Test()
{
InitAnInt(out n); // This is OK
InitAnInt(out i); // ERROR: A property or indexer may not be passed
// as an out or ref parameter
}
}
在类中,你不应该创建公共字段/变量,因为你永远不知道什么时候需要将其更改为具有get和set访问器,那么你就不知道会破坏哪些代码,特别是如果你有客户端对你的API进行编程。
此外,你可以为get和set使用不同的访问修饰符,例如{get; private set;}将get设置为public,将set设置为声明类的私有属性。
我想分享一下我在这个主题上的发现。
像下面这样编写属性,是 .net 3.0 中的一种快捷方式调用“自动实现属性”。
public int MyProperty { get; set; }
这样可以减少您的输入量。声明属性的长方式如下:
private int myProperty;
public int MyProperty
{
get { return myProperty; }
set { myProperty = value; }
}
当您使用“自动实现属性”时,编译器将生成连接get和set到一些“k_BackingField”的代码。下面是使用Reflector反汇编的代码。
public int MyProperty
{
[CompilerGenerated]
get
{
return this.<MyProperty>k__BackingField;
}
[CompilerGenerated]
set
{
this.<MyProperty>k__BackingField = value;
}
}
从IL反汇编出的C#代码
同时为getter和setter方法连接了一条线路。
[CompilerGenerated]
public void set_MyProperty(int value)
{
this.<MyProperty>k__BackingField = value;
}
[CompilerGenerated]
public int get_MyProperty()
{
return this.<MyProperty>k__BackingField;
}
从IL反编译出的C#代码
当您将 setter 设置为 private 时,声明只读自动实现属性:
public int MyProperty { get; private set; }
编译器只会将"set"标记为私有。设置器和获取器方法是相同的。
public int MyProperty
{
[CompilerGenerated]
get
{
return this.<MyProperty>k__BackingField;
}
private [CompilerGenerated]
set
{
this.<MyProperty>k__BackingField = value;
}
}
从IL中反汇编的C#代码
所以我不确定为什么框架要求自动实现的属性同时有get和set。如果没有提供,它们本来可以不写set和setter方法的。但可能存在一些编译器级别的问题使得这很困难,我不清楚。
如果你看一下声明只读属性的长方式:
public int myProperty = 0;
public int MyProperty
{
get { return myProperty; }
}
然后看一下反汇编代码,setter根本不在那里。
public int Test2
{
get
{
return this._test;
}
}
public int get_Test2()
{
return this._test;
}
从IL反汇编的C#代码
因为你需要一些方式来将其与普通字段区分开来。
此外,拥有不同的访问修饰符也很有用,例如:
public int MyProperty { get; private set; }
另外,因为自C# 6.0以来(在Visual Studio 2015中,在此回答发布时可用于Ultimate Preview版本),您可以实现真正的只读属性:
public string Name { get; }
public string Name { get; } = "This won't change even internally";
public string Name { get; private set; }
public Constructor() { Name="As initialised"; }
public void Method() { Name="This might be changed internally. By mistake. Or not."; }
以下是上述示例的编译和可执行版本(在线查看点击这里)。
using System;
public class Propertier {
public string ReadOnlyPlease { get; private set; }
public Propertier() { ReadOnlyPlease="As initialised"; }
public void Method() { ReadOnlyPlease="This might be changed internally"; }
public override string ToString() { return String.Format("[{0}]",ReadOnlyPlease); }
}
public class Program {
static void Main() {
Propertier p=new Propertier();
Console.WriteLine(p);
// p.ReadOnlyPlease="Changing externally!";
// Console.WriteLine(p);
// error CS0272: The property or indexer `Propertier.ReadOnlyPlease' cannot be used in this context because the set accessor is inaccessible
// That's good and intended.
// But...
p.Method();
Console.WriteLine(p);
}
}
关于C# 6.0的其他好消息,官方预览视频在这里。
public int Foo;
public int Bar { }
那样或许可行,也就是说,编译器可能理解这种语法。
但接下来你会遇到一个空块具有语义意义的情况。这似乎很危险。
既然没有人提到它... 你可以让自动属性成为虚拟的并重写它:
public virtual int Property { get; set; }
public override int Property { get { return int.MinValue; } }