什么是C#中的自动属性,其目的是什么?


Answers:


88

当属性访问器中不需要其他逻辑时,将使用“自动属性”。
该声明将如下所示:

public int SomeProperty { get; set; }

它们只是语法糖,因此您无需编写以下更冗长的代码:

 private int _someField;
 public int SomeProperty 
 {
    get { return _someField;}
    set { _someField = value;}
 }

20
@Cody Gray @Stecya为什么我不能只使用public int SomeProperty;?我的意思是,如果这里根本没有私有变量,那为什么我们甚至需要属性?
user2048204 '16

5
@ user2048204,因为属性不同于变量blog.codinghorror.com/properties-vs-public-variables
Slai 2016年

1
@ user2048204有一个私有变量;这是一个自动生成的匿名私有字段。但是,您可以编写代码以通过公共属性名称从类内部访问它(在功能上与直接访问它相同,在这种情况下,访问器上没有其他逻辑)。
Sepster

1
当您使用ildasm工具探索自动实现的属性时,您会知道,在每个自动实现的属性后面都有自动创建私有数据成员的以下字段以及两个用作该私有字段的getter和setter的方法。
阿玛(Ammar)'18

1
Stecya / AustinWBryan的答案缺少某些内容。如果自动属性在幕后创建了一个私有字段,为什么接口可以定义自动属性却不能定义字段?自动属性不可能是“仅”语法糖,因为在接口中使用自动属性时会出现编译器错误。
格雷戈里·芬恩

42

编辑:稍微扩展一下,这些用于使更容易在类中具有私有变量,但允许它们在类外部可见(而不能修改它们)

哦,自动属性的另一个优点是您可以在接口中使用它们!(不允许任何类型的成员变量)

使用常规属性,您可以执行以下操作:

private string example;
public string Example 
{
    get { return example; }
    set { example = value; }
}

自动属性使您可以创建非常简洁的内容:

public string Example { get; set; }

因此,如果您想创建一个只能在类内部设置的字段,则可以执行以下操作:

public string Example { get; private set; }

这等效于:

private string example;
public string Example 
{
    get { return example; }
    private set { example = value; }
}

或在Java中:

private String example;

public String getExample() {
    return example;
}

private void setExample(String value) {
    example = value;
}

编辑:@Paya还提醒我:


1
我还要添加这两个链接:MSDNASP.NET Blog
Paya)

7
Java中的等效项根本不需要setExampleprivatesetter。
Moira

1
这应该是选择的答案,因为当前答案没有提供使用简单字段使用空get / get的实际原因(突然说,它只是声明了一种声明无用方法的简单方法)。
分钟

17

如果您问为什么要使用“属性”或“自动属性”,这就是其背后的设计原理。

一个重要的设计原则是您从不将字段公开,而是始终通过属性访问所有内容。这是因为您永远无法确定何时访问字段,更重要的是,何时设置字段。现在,很多时候,在设置或获取值时(例如,范围检查)不再需要任何处理。这就是创建自动属性的原因。它们是创建属性的一种简单的单行方法。它的后备存储由编译器创建。

尽管这是我甚至为内部程序所做的工作,但对于那些设计用于公共用途(出售,开放源代码等)的程序而言,这可能更为重要。如果使用自动属性,以后又决定需要在set或中执行其他操作,则get可以轻松更改代码而不会破坏公共接口。

更新资料

为了澄清下面的评论,如果所有代码都是您自己的,则否,那么对于您而言,属性和字段之间的差异可能不会太大。但是,如果您设计的库将被其他人使用,则在公共字段和属性之间来回切换会导致异常,除非首先重新编译使用该库的代码。

作为测试,我创建了一个库项目,并声明了一个名为的属性TestData。我创建了一个新项目来使用该库。一切都按预期工作。然后,我将属性更改为公共字段(名称保持不变),并在新库DLL上进行复制,而无需重新编译使用项目。结果是抛出异常,因为代码希望找到方法的属性methodget_TestDataset_TestData,但是不能通过方法访问字段。

Unhandled Exception: System.MissingMethodException: Method not found: 'Void TestLibrary.TesterClass.set_TestData(System.String)'.
   at TestLibraryConsumer.Program.Main(String[] args)

1
如果您使用自动属性,后来又决定需要在集合或获取中做其他事情,则可以轻松更改代码而不会破坏公共接口”。如果以后需要在赋值或读取值之前进行一些处理,则用相同名称的属性替换字段同样容易。但是,除非需要此处理,否则声明属性比声明字段没有明显的好处。因此,OP仍然有效(此答案描述了使用空的get / set方法的实际好处)。
分钟

2
@分钟。如果代码是您所有的,那您是对的。我已经更新了答案,以进一步阐明为什么在属性和字段之间切换仍然会出错。
吉姆(Jim)

3

它们只是一种编码快捷方式,可以节省程序员一些按键操作。无需输入所有内容:

private string _lastName;
public string LastName {
    get {
        return _lastName;
    }
    set {
        _lastName = value;
    }
}  

您可以输入:

public string LastName {
    get; set;
} 

并让编译器自动生成其余部分。


5
编译器还会创建一个私有的匿名后备字段,该字段只能通过属性的get和set访问器进行访问。
克里斯·富斯托

2

自动实现的属性(C#编程指南)中

在C#3.0和更高版本中,当属性访问器中不需要其他逻辑时,自动实现的属性可使属性声明更加简洁。它们还使客户端代码可以创建对象。
声明属性时,编译器会创建一个私有的匿名后备字段,该字段只能通过属性的get和set访问器进行访问。

class Person
{
       public string Name { get; set; }
}

2

为简化接受的答案,您还可以使用

public int SomeProperty { get; private set; }

它具有相同的效果,您不再需要为此创建另一个变量。


2
有趣的是,您仍然可以在构造函数中为public int SomeProperty { get; }(no private set)设置一个值,就好像您的隐式后备字段已标记一样readonly
鲁芬

当您希望拥有一个属性,而该属性需要由其他类“只能获取”,并能够通过此类中的其他方法进行更新时,此建议适用。
DragonSpit

1

在C#的早期版本中,为了使用属性,您需要创建一个字段来保存值(称为后备存储):

private string _something;
public string Prop { get { return _something; } }

从C#3.0开始,不再需要此要求,并且编译器将自动为您创建后备存储,因此无需声明_something字段。

您可以在此处阅读有关此问题的更多信息: http //msdn.microsoft.com/zh-cn/library/bb384054.aspx

希望这可以帮助。


它是C#3.0及更高版本。您链接到的文档在顶部说。
科迪·格雷

1

许多人已经指出,自动属性是语法糖-一种编写简单属性的简写方式。我将处理公共变量和公共属性之间的区别,以及为什么在两者之间切换时需要重新编译。采取以下措施:

public class MyClass
{
    public int MyPublicVariable = 0;

    public int MyPublicProperty
    {
        get;
        set;
    }
}

一旦从概念上进行编译,它实际上最终类似于以下内容:

public class MyClass
{
    public int MyPublicVariable = 0;

    private int MyPublicProperty = 0;

    public int get_MyPublicProperty()
    {
        return MyPublicProperty;
    }

    public void set_MyPublicProperty( int value )
    {
        MyPublicProperty = value;
    }
}

很久以前,发明了属性是一种定义get和set方法对的快速简便的方法。当代码传达意图并确保一致性时,它使代码更易读和易于理解。

MyClass myClass = new MyClass();

myClass.MyPublicVariable = 2;

myClass.MyPublicProperty = 2;

一旦进行了编译,从概念上讲,它最终类似于以下内容:

MyClass myClass = new MyClass();

myClass.MyPublicVariable = 2;

myClass.set_MyPublicProperty( 2 );

因此,优先选择公共属性而不是公共变量的原因之一是,如果您需要在代码演化过程中使用不同的逻辑,则代码的使用者不一定需要重新编译。这就是为什么它通常被认为是最佳做法。这也是发明自动属性的原因-可以在保持最佳实践的同时加快代码编写速度。

关于接口也有一些评论。接口本质上是一种契约,它保证在实现它们的任何类中某些方法的存在。从上面我们知道,属性代表一种或两种方法,因此它们在接口中可以正常工作。

希望这有所帮助。

这是另一个可能令人感兴趣的示例:

public class MyClass
{
    private int[] _myArray = new int[ 5 ];

    public int MyArray[ int index ]
    {
        get
        {
            return _myArray[ index ];
        }
        set
        {
            _myArray[ index ] = value;
        }
     }
}
public class MyClass
{
    private int[] _myArray = new int[ 5 ];

    public int get_MyArray( int index )
    {
        return _myArray[ index ];
    }

    public void set_MyArray( int index, int value )
    {
        _myArray[ index ] = value;
    }
}

请注意:我不完全记得反编译属性时使用的方法签名。我认为它是“ get_XXX”和“ set_XXX”,但可能是其他非常相似的东西。只要有理解,就没什么大不了的。最后,无论如何,它们都成为内存地址:-)


0

除了前面的答案中提到的方面之外,我还将注意到自动属性和字段之间的一些差异,因为它们看起来非常相似并且其用法实际上是相同的:

  • 可以在需要时轻松开发为“经典”属性,而无需与属性调用者达成任何合同
  • 在Visual Studio中进行开发时,允许在get / set上设置断点。当通过反射进行更改并且更改的来源不明显时,此功能特别有用

-1

对于任何VB.NET阅读器,其实现方式略有不同。例如:

''' <summary>The property is declared and can be initialized.</summary>
Public Property MyProperty As String = "SomeValue"

但是,可以通过在下划线前面添加前缀来显式使用关联的字段:

Dim sConcat As String = _MyProperty + _MyProperty
_MyProperty = sConcat

并在外部代码中:

Dim sMyValue As String = oMyClassObj.MyProperty ' = "SomeValueSomeValue"

就我个人而言,我更喜欢这种方法,因为当您使用内部字段或可能公开的属性时,您可以在使用的代码中清楚地看到。


-2

使用以下代码:

using System;

class My Class
{
    public string Dummy { get; set; }

    public My Class()
    {
        Dummy = "I'm dummy property";
    }
}

class Program 
{
    static void Main() 
    {
            var my Class = new My Class();
             Console .Write Line (my Class .Dummy);
    }
}

我不确定该答案会添加任何内容,因为它不会“对C#中的自动属性,它们的用途以及某些示例提供非常简单的说明”,也不会编译。
罗布
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.