C#自动属性 ​​- 为什么我要写“get; set;”?

时间:2008-12-04 13:10:51

标签: c# c#-3.0 automatic-properties

如果在C#自动属性中必须同时获取和设置,为什么我必须打扰指定“get; set;”一点都没有?

9 个答案:

答案 0 :(得分:63)

因为您可能想要一个只读属性:

public int Foo { get; private set; }

或只写属性:

public int Foo { private get; set; }

答案 1 :(得分:51)

错误:属性或索引器不能作为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
    }
}

你不应该在类上创建公共字段/变量,你永远不知道什么时候你想要改变它以获得&设置访问器,然后你不知道你要破解的代码,特别是如果你的客户端针对你的API编程。

此外,您还可以使用不同的访问修饰符来获取&设置,例如{得到; private set;}使get public和set private成为声明类。

答案 2 :(得分:16)

因为你需要某种方法将它与普通字段区分开来。

拥有不同的访问修饰符也很有用,例如

public int MyProperty { get; private set; }

答案 3 :(得分:16)

我想我会在这个主题上分享我的发现。

编码如下所示的属性,是.net 3.0快捷方式调用“自动实现的属性”。

public int MyProperty { get; set; }

这可以为您节省一些打字费用。声明属性的漫长道路是这样的:

private int myProperty;
public int MyProperty 
{
  get { return myProperty; }
  set { myProperty = value; } 
}

当您使用“自动实现的属性”时,编译器会生成代码以连接get并设置为某个“k_BackingField”。下面是使用Reflector的反汇编代码。

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}

反汇编来自IL的C#代码

还连接了setter和getter的方法。

[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 ”标记为私有。 setter和getter方法也是如此。

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    private [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}

反汇编来自IL的C#代码

所以我不确定为什么框架需要get;并设定;在一个自动实现的属性。如果没有提供,他们可能没有写过set和setter方法。但是可能有一些编译器级别的问题使得这很困难,我不知道。

如果你看一下声明只读属性的漫长道路:

public int myProperty = 0;
public int MyProperty
{
    get { return myProperty; }
}  

然后查看反汇编的代码。安装员根本就不存在。

public int Test2
{
    get
    {
        return this._test;
    }
}

public int get_Test2()
{
    return this._test;
}

反汇编来自IL的C#代码

答案 4 :(得分:4)

编译器需要知道您是否希望它生成一个getter和/或setter,或者可能正在声明一个字段。

答案 5 :(得分:2)

如果属性没有访问器,编译器将如何将其与字段分开?什么会将它与一个领域分开?

答案 6 :(得分:2)

嗯,显然你需要一种消除字段和属性之间歧义的方法。但是必需的关键字真的有必要吗例如,很明显这两个声明是不同的:

public int Foo;
public int Bar { }

这可行。也就是说,它是编译器可以理解的语法。

然后你会遇到空块具有语义含义的情况。这似乎不稳定。

答案 7 :(得分:2)

由于没有人提到它......你可以将auto-property设为虚拟并覆盖它:

public virtual int Property { get; set; }

如果没有获取/设置,它将如何被覆盖?请注意,您可以override the getter and not the setter

public override int Property { get { return int.MinValue; } }

答案 8 :(得分:2)

此外,因为从C#6.0开始(在Visual Studio 2015中,在版本Ultimate Preview中提供此答案时),您可以实现真正的只读属性:

public string Name { get; }
public string Name { get; } = "This won't change even internally";

...与目前使用公共getter / private setter对的不完美解决方法相反:

public string Name { get; private set; }

public Constructor() { Name="As initialised"; }
public void Method() { Name="This might be changed internally. By mistake. Or not."; }

以上示例(在线编译和可执行here)。

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的其他美味新闻可作为官方预览视频here