繁体   English   中英

为什么我们在类中创建一个私有变量然后设置属性?

[英]Why do we create a private variable inside a class and then set property?

为什么我们在一个类中创建一个私有变量,然后在c#中的以下行中创建一个公共属性? 我也没有得到获取和设置属性的概念。

我的意思是为什么我们这样做

 public class MyClass
    {
        private string _myProperty;

        public string MyProperty
        {
           get
           { return _myProperty; }
           set
           { _myProperty = value; }
    }

或这个

public class MyClass
{
    public string MyProperty {get;set;}
}

我的问题与此问题非常类似: 为什么我们需要创建类变量来获取和设置属性?

上面的线程似乎没有解决我的问题。 有人请详细说明:

  • 为什么首先创建私有变量然后从中创建公共属性? 为什么不一步?
  • 我们需要什么'获得'和'设置'? 为什么两种方法使用它,有什么区别?

问题的答案可能太长了。 但即使你花费宝贵的时间来恰当地解释一个问题,我也不仅仅是有义务。 提前致谢 :)

为什么首先创建私有变量然后从中创建属性? 为什么不一步?

如果要在设置属性之前进行某种验证,则使用私有变量,或者基本上抽象出类中有关该属性的内容。 例如,如果您希望给定变量在一个范围内:

private int foo;
public int Foo 
{
    get { return foo; }
    set 
    {
        if (value < 0 || value > 10)
        {
            throw new ArgumentOutOfRangeException(value);
        }

        foo = value;
    }
}

我们需要什么'获得'和'设置'以及为什么有两种方法可以使用它?

C#-3.0带来了自动属性 ,因为MSFT看到很多人使用属性“有一天我想要验证我的变量或改变内部实现的可能性”。 公开属性而不是变量允许您稍后添加任何代码验证,而不会破坏与属性的任何调用者的现有“合同”。

@JonSkeet很好地拼凑出来,在他的C#In Depth中表现平平(谢谢@Sriram):

  • 有更多细粒度的访问控制和属性。
  • 需要它是公开可获得的,但实际上只希望它设置为受保护的访问? 没问题(从C#2开始,至少)。
  • 想要在值发生变化时闯入调试器? 只需在setter中添加断点即可。
  • 想记录所有访问权限? 只需将日志记录添加到getter即可。
  • 属性用于数据绑定; 字段不是。

将字段设为私有并将其作为属性公开可提供控制set和get操作的类功能,这在不同的场景中非常有用。

验证

该类可以在将提供的数据存储到字段之前对其进行验证:

class WeatherInfo {
      private static readonly int minDegree = -273;
      private static readonly int maxDegree = 75;
      private int degree;
      public int Degree {
         get {
             return this.degree;
         }
         set {
             if (value < minDegree || value > maxDegree) {
                 throw new ArgumentOutOfRangeException();
             }
         }
      }
      ..
      ..
}

字段值无效

在某些情况下,对象的字段可能没有有意义的值。 提供getter方法,允许对象通知它的客户端。

class User {
    private DateTime loginTime;
    private bool loggedIn;
    ..
    ..
    public DateTime LoginTime {
        get {
            if (!this.loggedIn) {
               throw new InvalidOperationException();
            }
            return loginTime;
        }
    }
}

不提供setter或限制访问setter

使用属性而不是字段的另一个好处是它允许对象限制对字段的访问。 在前面的例子中,我们有一个没有setter的方法。 此方法的另一个用途是限制对setter的访问。

class Customer {
      private string name;
      private string family;
      private string nameFamily;

      public string name {
           get {
               return this.name;
           }
           private set {
               if (!string.Equals(name, value)) {
                    this.name = value;
                    this.UpdateNameFamily();
               }
          }
      }
      private void UpdateNameFamily() {
          this.nameFamily = string.Format("{0} {1}", this.name, this.family);
      }
      ..
      ..
}

正如您所看到的,这种方法的好处是它允许类在属性从类内部更改时执行某些操作。

提高事件

用于引发XXXXChanged事件的常见模式是检查setter中的值并在事件发生更改时引发事件:

class Question {
    public event EventHandler AnsweredChanged;
    private bool isAnswered;
    ..
    ..
    public bool IsAnswered {
        get {
            return this.isAnswered;
        }
        set {
            if (this.isAnswered != value) { 
                this.OnIsAnsweredChanged();
            }
        }
    }
    private void OnIsAnsweredChanged() {
         if (this.AnsweredChanged!= null) {
              this.AnsweredChanged(this, EventArgs.Empty);
         }
    }
}

这种方法的另一个常见用途是实现INotifyPropertyChanged接口。

无逻辑模型

即使您不需要属性可以实现的任何内容,并且您拥有无逻辑类,但最好不要将类字段暴露给类的外部世界。 在这种情况下,您可以简单地使用自动属性作为遵循最佳实践的快捷方式,而无需直接定义字段。

class UserModel {
      public string Username {
           get;
           set;
      }
      public DateTime Birthdate {
           get;
           set;
      }
      ..
      ..
}

你的例子都是等价的。 第二个是第一个的语法糖。

Property的原因是创建类的内部状态的抽象。 例如,如果您使用公共字段,则在没有更改类的接口的情况下,您没有机会更改它。 使用属性隐藏实现,其余代码不会改变任何内容。 例:

public class MyClass
{
    public string MyProperty {get;set;}
}

我想更改实现细节以直接从db存储/检索值

public class MyClass
{
    public string MyProperty {
        get{_db.GetValue('myFiled');}
        set{_db.SetValue('myField', value)}}
}

正如您所看到的,实现发生了巨大变化,但类接口仍然相同。

类的内部逻辑应该与外界保持隐藏
假设您需要一个可以从外部访问的字段,但只能从类内部设置,没有属性,您将不得不这样做:

public class Example
{
   private String _data;

   public String GetData()
   {
      return _data;
   }
}

使用属性,您可以通过以下方式执行相同的操作:

public class Example
{
   private String _data;

   public String Data { get; private set}       

}

缩短了代码并使其更加干净,并且您可以完全控制字段可访问性,但属性具有很多优点 例如,假设您的私有字段需要一些逻辑,假设在字段被分配之前从外部访问该属性。
请考虑以下示例:

public class Example
{
   private MyCustomClass _data;

   public MyCustomClass Data { get { return _data }; private set { _data = value;}}       

}

如果还没有分配_data,如果你尝试使用它,你会在代码中的某个地方得到一个null异常,但你可以实现一些逻辑,避免它像这样:

public class Example
{
   private MyCustomClass _data;

   public MyCustomClass Data
   { 
      get
      {
         if(_data == null)
           _data = new MyCustomClass();
         return _data;
      }
      private set { _data = value;} }             
}

所以你也可以用属性实现 逻辑

此外,请记住,当您创建这样的属性时

public class Example
{
   public String MyData{ get; set;}
}

实际上,当你编译它时,编译器将它转换为这样的东西:

public class Example
{
   private String _myData;
   public String MyData{ get {return _myData}; set { _myData = value}}
}



最后假设将来你需要将设置值的逻辑更改为该字段,如果你使用了公共字段,你将需要做很多工作但是如果你使用了属性,你只需要改变属性的逻辑和你这样做可维护性也是一个很好的属性!

编辑
关于绑定大多数框架都使用属性来绑定prupose

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM