【问题标题】:C# Automatic Properties - Why Do I Have To Write "get; set;"?C# 自动属性 ​​- 为什么我必须编写“get; set;”?
【发布时间】:2008-12-04 13:10:50
【问题描述】:

如果在 C# 自动属性中 get 和 set 都是强制性的,我为什么还要费心指定“get; set;”有吗?

【问题讨论】:

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


    【解决方案1】:

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

    public int Foo { get; private set; }
    

    或只写属性:

    public int Foo { private get; set; }
    

    【讨论】:

    • 您还可以添加各种修饰符,如保护等。
    • 是的,其他人怎么说...您需要一种区分字段和属性的方法。
    • 附注:这里有只读字段的概念。该框架将确保这些只写一次。它与私有的 setter 或 getter 不同,如果你有访问权限就可以编写。
    • 另外,看看我的回答,这不仅仅是访问级别,编译器对字段和属性的处理方式不同。
    • @BrianGenisio 这些属性并不是真正的只读属性,而是私有写入,直到现在还很接近,但是在 C# 6.0 (Visual Studio 2015) 中我们有真正的只读属性(@ 987654321@)。耶!
    【解决方案2】:

    错误:属性或索引器不能作为 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 使用不同的访问修饰符,例如{得到; private set;} 使 get public 和 set 对声明类私有。

    【讨论】:

      【解决方案3】:

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

      像下面这样编写一个属性,是一个 .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 设置为私有:

       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; }
      }  
      

      然后看反汇编代码。 setter 根本不存在。

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

      从 IL 中反汇编的 C# 代码

      【讨论】:

      • 自动属性需要私有 set 方法,否则您将永远无法将值设置为任何值,这将毫无意义。您可以从非自动属性中排除 setter,因为支持字段提供了一种在内部更改值的方法。
      • 好点,这是正确的。因为您没有私有变量,所以在使用自动实现的属性时,如果值不存在,您知道设置值的方法。
      【解决方案4】:

      因为您需要一些方法来将其与普通字段区分开来。

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

      public int MyProperty { get; private set; }
      

      【讨论】:

      • 但是公共字段没用。
      • 同意。语法可能部分归因于安德斯先生不想在语言中引入新关键字。
      • Earwicker:我发现公共字段在我的 Vector2f 类中很有用——它们大大加快了程序速度(与属性相比),而且这个类很简单,我永远不需要更改实施。
      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        如果属性没有访问器,编译器如何将它与字段分开?什么将它与字段分开?

        【讨论】:

          【解决方案7】:

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

          public int Foo;
          public int Bar { }
          

          这可能行得通。也就是说,这是一种编译器可以理解的语法。

          但是你会遇到一个空块具有语义意义的情况。这似乎很不稳定。

          【讨论】:

            【解决方案8】:

            由于没有人提到它...您可以将自动属性设为虚拟并覆盖它:

            public virtual int Property { get; set; }
            

            如果没有get/set,它会如何被覆盖?请注意,您可以override the getter and not the setter

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

            【讨论】:

              【解决方案9】:

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

              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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-05-09
                • 2010-10-09
                • 2022-06-15
                • 1970-01-01
                • 2017-01-15
                相关资源
                最近更新 更多