首页 文章

属性与字段:需要帮助掌握属性对字段的使用

提问于
浏览
34

首先,我已经阅读了关于这个主题的帖子列表,我不觉得我已经掌握了属性,因为我已经了解了封装和字段修饰符(private,public..ect) .

我学习的C#的一个主要方面是通过使用封装在代码中保护数据的重要性 . 我认为'我理解这是因为使用修饰符(私有,公共,内部,受保护)的能力 . 然而,在了解了属性后,我不仅理解了属性的使用,而且还了解了C#中数据保护的整体重要性/能力(我理解为封装) .

更具体地说,当我到达C#中的属性时,我读过的所有内容都是你应该尝试使用它们代替字段,因为:

1) 它们允许您在直接直接访问字段时无法更改数据类型 .

2) 他们为数据访问添加了一定程度的保护

然而,根据我的想法,我已经了解了字段修饰符的使用#2,在我看来属性只是生成了额外的代码,除非你有一些理由改变类型(#1) - 因为你是(或多或少)创建隐藏方法来访问字段而不是直接访问 .

然后可以将整个修饰符添加到属性中,这进一步使我对属性访问数据的需要的理解变得复杂 .

我已经阅读了不同作者关于“属性”的一些章节,并且没有人真正解释了对属性与字段与封装(以及良好的编程方法)的良好理解 .

Can someone explain:

1) 为什么我要使用属性而不是字段(特别是当它出现时我只是添加其他代码

2) 任何有关识别属性使用的提示,并且在跟踪其他人的代码时,不会将它们视为简单的方法(除了get; set明显)?

3) 任何关于何时使用什么的良好编程方法的一般经验法则?

谢谢和抱歉这篇长篇文章 - 我不想只问一个问题100x而不解释为什么我再问它 .

12 回答

  • 21

    需要注意的是,像“Threading.Interlocked.Increment”这样的东西可以用于字段,但不能用于属性 . 如果两个线程同时在SomeObject.LongIntegerField上调用Threading.Interlocked.Increment,即使没有其他锁定,该值也会增加2 . 相比之下,如果两个线程同时在SomeObject.LongIntegerProperty上调用Threading.Interlocked.Increment,则该属性的值可能会增加2,或者增加1,或增加-4,294,967,295,或者知道其他什么值(可以写入属性以使用锁定来防止该场景中除一个或两个以外的值,但无法写入以确保正确的增量为2) .

  • 9

    属性是覆盖字段以强制封装的首选方式 . 但是,它们的功能在于您可以公开具有不同类型的属性并封送转换;你可以改变访问修饰符;它们用于WinForms数据绑定;它们允许您嵌入轻量级的每个属性逻辑,例如更改通知;等等

    在查看其他人的代码时,属性对方法具有不同的智能感知图标 .

    如果您认为属性只是额外的代码,我会反对坚持使用它们,但通过从字段自动生成属性(右键单击 - >重构 - >封装字段......)可以让您的生活更轻松 .

  • 0

    1)为什么我想要使用属性而不是字段(特别是当它出现时我只是添加额外的代码

    您应该始终使用属性 . 它们抽象直接访问字段(如果您不创建字段,则为您创建) . 即使该属性除了设置值之外什么都不做,它可以在以后保护您 . 稍后将字段更改为属性是一个重大更改,因此如果您有一个公共字段并希望将其更改为公共属性,则必须重新编译最初访问该字段的所有代码 .

    2)在跟踪其他人的代码时,是否有关于识别属性的使用以及不将它们视为简单方法(除了get; set明显)之外的任何提示?

    我并不完全确定你在问什么,但是在追踪别人的代码时,你应该总是假设该属性正在做的事情不仅仅是获取和设置一个值 . 尽管在getter和setter中没有放入大量代码是公认的惯例,但你不能只假设它是一个属性,它会表现得很快 .

    3)任何关于何时使用什么的良好编程方法的一般经验法则?

    我总是使用属性来获取和设置方法 . 这样我可以稍后添加代码,如果我需要检查值是否在某些范围内,而不是null等 . 不使用属性,我必须返回并将这些检查放在我直接访问该字段的每个地方 .

  • 7

    关于Properties的一个好处是getter和setter可以有不同的访问级别 . 考虑一下:

    public class MyClass {
    
      public string MyString { get; private set; }
    
      //...other code
    }
    

    此属性只能在内部更改,例如在构造函数中 . 阅读依赖注入 . 构造函数注入和Property注入都处理来自某种形式的外部配置的设置属性 . 那里有很多框架 . 如果您深入研究其中的一些,您将对 properties 及其使用有一个良好的感觉 . 依赖注入也将帮助您解决关于良好实践的第3个问题 .

    在查看其他人的代码时,您可以判断某些东西是方法还是属性,因为它们的图标不同 . 此外,在Intellisence中,属性摘要的第一部分是Property .

  • 11

    属性允许您执行除设置之外的操作或在使用它们时获取值 . 最值得注意的是,它们允许您执行验证逻辑 .

    最佳实践是将任何公开的 property 公开 . 这样,如果您稍后更改set / get逻辑,则只需重新编译您的类,而不是每个链接的类 .

  • 2

    why I would want to use properties instead of fields (especially when it appears I am just adding additional code

    您希望在字段上使用属性,因为当您使用属性时可以将事件与它们一起使用,因此在您希望在属性更改时执行某些操作时,可以将一些处理程序绑定到PropertyChanging或PropertyChanged事件 . 在字段的情况下,这是不可能的 . 字段可以是公共的,也可以是私有的或受保护的,如果是道具,您可以将它们设为只读,但可以私下写入 .

    any tips on recognizing the use of properties and not seeing them as simply methods (with the exception of the get;set being apparent) when tracing other peoples code?

    当每次调用返回值时,应该使用一个方法,当返回值不是那么大的动态时,应该使用一个属性 .

    Any general rules of thumb when it comes to good programming methods in relation to when to use what?

    是的,我强烈建议阅读Framework Design guidelines以获得良好编程的最佳实践 .

  • 3

    我打算说Properties(setters)是一个提升像NotifyPropertyChanged这样的事件的好地方,但是有人打败了我 .

    考虑属性的另一个好理由:假设您使用工厂构造一些具有默认构造函数的对象,并通过其属性准备对象 .

    new foo(){Prop1 = "bar", Prop2 = 33, ...};
    

    但是如果外部用户新建了你的对象,也许有些属性你希望它们看作只读而不能设置(只有工厂应该能够设置它们)?您可以将setter设置为内部 - 当然,这仅适用于对象的类与工厂在同一个程序集中的情况 .

    还有其他方法可以实现这一目标,但如果您正在进行基于接口的开发,或者将库公开给其他人等,则使用属性和不同的访问者可见性是一个很好的考虑因素 .

  • 1

    使用字段通常在私有类中实现,不打算与其他类共享数据 . 当我们希望我们的数据可以被其他类访问时,我们使用能够通过 getset 与其他类共享数据的属性名为 Auto Properties 的方法可以访问私有类中的数据,也可以同时使用同一类中的访问修饰符,允许类私有地使用数据作为数据字段,同时将私有字段链接到产生数据的属性其他类也可以访问,请看这个简单的例子:

    private string _name;  
    public string Name    
    {
       get
         {
           return _name;
         }
       set
         {
          _name = value;
         }
    }
    

    专用字符串 _name 仅由类使用,而 Name 属性可由同一名称空间中的其他类访问 .

  • 0
    • 您可能想要使用字段属性有几个原因,这里只是一对:

    一个 . 通过以下方式

    public string MyProperty { get; private set; }
    

    你正在使该 properties “只读” . 没有人使用你的代码可以修改它的 Value . 在某些情况下,这不是严格正确的(如果您的属性是列表),但这些是已知的并且有解决方案 .

    湾如果您决定需要增加代码使用属性的安全性:

    public string MyProperty
    {
        get { return _myField; }
        set
        {
            if (!string.IsNullOrEmpty(value))
            {
                _myField = value;
            }
        }
    }
    
    • 你可以告诉他们're properties because they don't有 () . 编译器会告诉您是否尝试添加括号 .

    • 始终使用属性被认为是一种好习惯 .

  • 1

    您不必担心通过属性访问字段所需的额外代码,它将被JIT编译器“优化”(通过内联代码) . 除非它太大而无法内联,但无论如何你还需要额外的代码 .

    用于定义简单属性的额外代码也是最小的:

    public int MyProp { get; set; } // use auto generated field.
    

    当您需要自定义时,您可以在以后定义您自己的字段 .

    所以你留下了额外的封装/数据保护层,这是一件好事 .

    我的规则: expose fields always through properties

  • 8

    虽然我绝对不喜欢直接向公众公开字段,但还有另一件事:字段不能通过接口公开;属性可以 .

  • 2

    在许多情况下,使用简单的字段不会造成损害,但是
    稍后可以更轻松地更改属性,即,如果要在值更改时添加事件或想要执行某些值/范围检查 .

    此外,如果您有多个相互依赖的项目,则必须重新编译所有依赖于将字段更改为属性的项目 .

相关问题