首先,我已经阅读了关于此主题的帖子列表,并且由于我对封装和字段修饰符(private,public..ect)的了解,我不觉得自己掌握了属性。< / p>
我开始学习C#的一个主要方面是使用封装在代码中保护数据的重要性。我认为'我理解这是因为使用修饰符的能力(私人,公共,内部,受保护)。然而,在了解了属性之后,我不仅理解了属性的使用,而且还理解了C#中数据保护(我理解为封装)的整体重要性/能力。
更具体地说,当我到达C#中的属性时,我读过的所有内容都是你应该尝试使用它们代替字段,因为:
1)它们允许您在直接直接访问字段时无法更改数据类型。
2)他们为数据访问添加了一定程度的保护
然而,根据我的想法,我已经了解了字段修饰符的使用#2,在我看来属性只是生成了额外的代码,除非你有一些改变类型的理由(#1) - 因为你(或多或少)创建隐藏方法来访问字段而不是直接访问字段。
然后可以将整个修饰符添加到属性中,这进一步使我对属性访问数据的需要的理解变得复杂。
我已经阅读了不同作者关于“属性”的一些章节,但没有一章真正解释了对属性与字段与封装(以及良好的编程方法)的良好理解。
有人可以解释一下:
1)为什么我要使用属性而不是字段(特别是当它出现时我只是添加其他代码
2)有关识别属性使用的任何提示,并且在跟踪其他人的代码时没有将它们视为简单的方法(除了get; set明显)?
3)关于什么时候使用什么的好的编程方法,有什么一般的经验法则?
感谢并且抱歉这篇长篇文章 - 我不想仅仅问一个100x的问题,而不解释为什么我再问这个问题。
答案 0 :(得分:21)
1)为什么我想要使用属性 而不是字段(特别是当它 似乎我只是添加额外的 代码
您应该尽可能使用属性。它们抽象直接访问字段(如果您不创建字段,则为您创建)。即使该属性除了设置值之外什么都不做,它可以在以后保护您。稍后将字段更改为属性是一个重大更改,因此如果您有一个公共字段并希望将其更改为公共属性,则必须重新编译最初访问该字段的所有代码。
2)关于识别使用的任何提示 属性,而不是看到它们 简单的方法(除了 得到;设置明显)何时 追踪其他人的代码?
我并不完全确定你在问什么,但是当跟踪别人的代码时,你应该总是假设该属性正在做的事情不仅仅是获取和设置一个值。尽管在getter和setter中没有放入大量代码是公认的做法,但你不能只假设它是一个属性,它会表现得很快。
3)任何一般的经验法则 来自于良好的编程方法 关于何时使用什么?
我总是使用属性来获取和设置方法。这样我可以稍后添加代码,如果我需要检查值是否在某些范围内,而不是null等。不使用属性,我必须返回并将这些检查放在我直接访问该字段的每个地方。
答案 1 :(得分:11)
关于Properties的一个好处是getter和setter可以有不同的访问级别。考虑一下:
public class MyClass {
public string MyString { get; private set; }
//...other code
}
此属性只能在内部更改,例如在构造函数中更改。阅读依赖注入。构造函数注入和Property注入都处理来自某种形式的外部配置的设置属性。那里有很多框架。如果您深入研究其中一些,您将对物业及其使用有一个良好的感觉。依赖注入也将帮助您解决关于良好实践的第三个问题。
在查看其他人的代码时,您可以判断某些内容是方法还是属性,因为它们的图标不同。此外,在Intellisence中,属性摘要的第一部分是Property。
答案 2 :(得分:9)
您不必担心通过属性访问字段所需的额外代码,它将被JIT编译器“优化”(通过内联代码)。除非它太大而无法内联,但无论如何你还需要额外的代码。
用于定义简单属性的额外代码也很少:
public int MyProp { get; set; } // use auto generated field.
当您需要自定义时,您可以稍后定义自己的字段。
所以你留下了额外的封装/数据保护层,这是一件好事。
我的规则:始终通过属性公开字段
答案 3 :(得分:8)
您可能希望在字段上使用属性有几个原因,这里只是一对:
一个。通过以下
public string MyProperty { get; private set; }
您正在将该属性设为“只读”。没有人使用你的代码可以修改它的价值。在某些情况下,这不是严格正确的(如果您的财产是一个清单),但这些是已知的并且有解决方案。
湾如果您决定需要提高代码使用属性的安全性:
public string MyProperty
{
get { return _myField; }
set
{
if (!string.IsNullOrEmpty(value))
{
_myField = value;
}
}
}
您可以告诉他们属性,因为他们没有()
。如果您尝试添加括号,编译器会告诉您。
始终使用属性是一种良好的做法。
答案 4 :(得分:7)
虽然我绝对不喜欢直接向公众公开字段,但还有另一件事:字段不能通过接口公开;属性可以。
答案 5 :(得分:3)
在许多情况下,使用简单字段不会造成损害,但
a属性可以在以后更容易地更改,即,如果您想在值更改时添加事件或想要执行某些值/范围检查。
此外,如果您有多个相互依赖的项目,则必须重新编译所有依赖于将字段更改为属性的项目。
答案 6 :(得分: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以获得良好编程的最佳做法。
答案 7 :(得分:2)
使用字段通常在私有类中实现,不打算与其他类共享数据。当我们希望其他类可以访问我们的数据时,我们使用能够通过{{1}与其他类共享数据的属性和get
这些访问方法称为set
,可以访问私有类中的数据,也可以在同一个类中使用访问修饰符,允许类私下使用数据作为数据字段和同时将私有字段链接到使其他类可以访问数据的属性,请参阅以下简单示例:
Auto Properties
私有字符串private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
仅由类使用,而_name
属性可由同一名称空间中的其他类访问。
答案 8 :(得分:1)
属性是覆盖字段以强制执行封装的首选方法。但是,它们的功能在于您可以公开具有不同类型的属性并封送转换;你可以改变访问修饰符;它们用于WinForms数据绑定;它们允许您嵌入轻量级的每个属性逻辑,例如更改通知;等
在查看其他人的代码时,属性对方法有不同的智能感知图标。
如果您认为属性只是额外的代码,我会反对坚持使用它们但是通过从字段自动生成属性(右键单击 - &gt; Refactor - &gt; Encapsulate Field ...)可以让您的生活更轻松。
答案 9 :(得分:1)
属性允许您执行除设置之外的操作或在使用它们时获取值。最值得注意的是,它们允许您进行验证逻辑。
最佳做法是向公众公开财产。这样,如果你以后更改了set / get逻辑,你只需要重新编译你的类,而不是每个链接它的类。
答案 10 :(得分:1)
我打算说,属性(设置者)是提升像NotifyPropertyChanged这样的事件的好地方,但有人打败了我。
考虑属性的另一个好理由:假设您使用工厂构造一些具有默认构造函数的对象,并通过其属性准备对象。
new foo(){Prop1 = "bar", Prop2 = 33, ...};
但是如果外部用户新增了你的对象,也许有些属性你希望他们看到只读而不能设置(只有工厂应该能够设置它们)?你可以将setter设置为内部 - 当然,这只适用于对象的类与工厂在同一个程序集中。
还有其他方法可以实现这一目标,但如果您正在进行基于接口的开发,或者将库公开给其他人等,则使用属性和不同的访问者可见性是一个很好的考虑因素。
答案 11 :(得分:1)
有一点需要注意,“Threading.Interlocked.Increment”之类的东西可以用于字段,但不能用于属性。如果两个线程同时在SomeObject.LongIntegerField上调用Threading.Interlocked.Increment,即使没有其他锁定,该值也会增加2。相反,如果两个线程同时在SomeObject.LongIntegerProperty上调用Threading.Interlocked.Increment,则该属性的值可能会增加2,或增加1,或增加-4,294,967,295,或者谁知道其他值(属性可以写入)在该场景中使用锁定防止除一个或两个以外的值,但无法写入以确保正确的增量为2)。