在C#中,是什么使字段与属性不同?何时应该使用字段而不是属性?
当前回答
由于他们中的许多人已经解释了财产和Field的技术优缺点,现在是时候进入实时示例了。
1.财产允许您设置只读访问级别
考虑dataTable.Rows.Count和dataTable.Column[i].Caption的情况。它们来自dataTable类,对我们来说都是公共的。对它们的访问级别的不同之处在于,我们不能将值设置为dataTable.Rrows.Count,但我们可以读写dataTable.Colomn[i].Taption。这可以通过Field实现吗?不这只能通过财产完成。
public class DataTable
{
public class Rows
{
private string _count;
// This Count will be accessable to us but have used only "get" ie, readonly
public int Count
{
get
{
return _count;
}
}
}
public class Columns
{
private string _caption;
// Used both "get" and "set" ie, readable and writable
public string Caption
{
get
{
return _caption;
}
set
{
_caption = value;
}
}
}
}
2.PropertyGrid中的财产
您可能在Visual Studio中使用了Button。它的财产显示在PropertyGrid中,如Text、Name等。当我们拖放按钮时,当我们单击财产时,它将自动找到类button并过滤财产,并在Property Grid中显示该类(其中PropertyGrid不会显示Field,即使它们是公共的)。
public class Button
{
private string _text;
private string _name;
private string _someProperty;
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
[Browsable(false)]
public string SomeProperty
{
get
{
return _someProperty;
}
set
{
_someProperty= value;
}
}
在PropertyGrid中,将显示财产Name和Text,但不显示SomeProperty。为什么?因为财产可以接受属性。如果[可浏览(false)]为false,则不会显示。
3.可以在财产中执行语句
public class Rows
{
private string _count;
public int Count
{
get
{
return CalculateNoOfRows();
}
}
public int CalculateNoOfRows()
{
// Calculation here and finally set the value to _count
return _count;
}
}
4.绑定源中只能使用财产
绑定源帮助我们减少代码行数。BindingSource不接受字段。为此,我们应该使用财产。
5.调试模式
考虑我们使用Field来保存值。在某些时候,我们需要调试并检查该字段的值在哪里变为空。当代码行数超过1000行时,这将很难做到。在这种情况下,我们可以使用Property,并可以在Property中设置调试模式。
public string Name
{
// Can set debug mode inside get or set
get
{
return _name;
}
set
{
_name = value;
}
}
其他回答
财产显示字段。字段应该(几乎总是)对类保持私有,并通过get和set财产进行访问。财产提供了一个抽象级别,允许您更改字段,同时不影响使用类的事物访问字段的外部方式。
public class MyClass
{
// this is a field. It is private to your class and stores the actual data.
private string _myField;
// this is a property. When accessed it uses the underlying field,
// but only exposes the contract, which will not be affected by the underlying field
public string MyProperty
{
get
{
return _myField;
}
set
{
_myField = value;
}
}
// This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
// used to generate a private field for you
public int AnotherProperty { get; set; }
}
@Kent指出,财产不需要封装字段,它们可以对其他字段进行计算,也可以用于其他目的。
@GSS指出,您还可以在访问属性时执行其他逻辑,例如验证,这是另一个有用的功能。
在大多数情况下,它将是您访问的属性名,而不是变量名(字段)。原因是,在.NET中,尤其是在C#中,它被认为是保护类中的每一条数据的良好做法,无论是实例变量还是静态变量(类变量),因为它与类相关联。
使用相应的财产保护所有这些变量,这些属性允许您定义、设置和获取访问器,并在操作这些数据片段时执行验证等操作。
但在其他情况下,如Math类(System命名空间),类中内置了一些静态财产。其中一个是数学常数PI
例如数学PI
因为PI是一块定义良好的数据,我们不需要有多个PI副本,它总是相同的值。因此,静态变量有时用于在类的对象之间共享数据,但也通常用于只需要一个数据副本的常量信息。
这里的第二个问题,“什么时候应该使用字段而不是属性?”,在另一个答案中只简短地提到了这个问题,也有点像这个问题,但没有太多细节。
总的来说,所有其他答案都是关于良好设计的一针见血的:比起暴露字段,更喜欢暴露财产。虽然你可能不会经常说“哇,想象一下,如果我把这里变成了一块地而不是一块地,情况会变得多么糟糕”,但想到你会说“哇!谢天谢地,我在这里用了一块土地而不是一处地”的情况,那就难得多了
但与财产相比,字段有一个优点,那就是它们可以用作“ref”/“out”参数。假设您有一个具有以下签名的方法:
public void TransformPoint(ref double x, ref double y);
假设您希望使用该方法来转换如下创建的数组:
System.Windows.Point[] points = new Point[1000000];
Initialize(points);
因为X和Y是财产,所以我认为这是最快的方法:
for (int i = 0; i < points.Length; i++)
{
double x = points[i].X;
double y = points[i].Y;
TransformPoint(ref x, ref y);
points[i].X = x;
points[i].Y = y;
}
这会很好的!除非你的测量结果证明了这一点,否则没有理由大惊小怪。但我认为,从技术上来说,它并不能保证像这样快:
internal struct MyPoint
{
internal double X;
internal double Y;
}
// ...
MyPoint[] points = new MyPoint[1000000];
Initialize(points);
// ...
for (int i = 0; i < points.Length; i++)
{
TransformPoint(ref points[i].X, ref points[i].Y);
}
我自己进行了一些测量,带字段的版本与带财产的版本(.NET 4.6、Windows 7、x64、发布模式、未附加调试程序)相比,大约需要61%的时间。TransformPoint方法的成本越高,差异就越不明显。若要自己重复此操作,请将第一行注释掉,并将其未注释掉。
即使上述方法没有性能优势,但在其他地方使用ref和out参数可能会有好处,例如在调用Interlocked或Volatile方法家族时。注意:如果这对您来说是新的,Volatile基本上是一种获得Volatile关键字提供的相同行为的方法。因此,就像volatile一样,它并没有像名字所暗示的那样神奇地解决所有线程安全问题。
我当然不想让人觉得我在提倡你说“哦,我应该开始公开字段,而不是财产。”关键是,如果你需要在调用中定期使用这些成员来接受“ref”或“out”参数,尤其是在可能是简单值类型的东西上,它不太可能需要财产的任何增值元素,那么可以进行一个参数。
基本区别和一般区别是:
领域
始终给予get和set访问权限不会造成副作用(引发异常、调用方法、更改字段(获取/设置的字段除外)等)
财产
并非总是同时提供get和set访问权限CAN导致副作用
想想看:你有一个房间和一扇门可以进入这个房间。如果你想检查谁是如何进来并保护你的房间的,那么你应该使用财产,否则他们不会是任何门,每个人都很容易进来,没有任何规定
class Room {
public string sectionOne;
public string sectionTwo;
}
Room r = new Room();
r.sectionOne = "enter";
人们很容易进入第一区,没有任何检查
class Room
{
private string sectionOne;
private string sectionTwo;
public string SectionOne
{
get
{
return sectionOne;
}
set
{
sectionOne = Check(value);
}
}
}
Room r = new Room();
r.SectionOne = "enter";
现在你检查了这个人,知道他是否有什么不好的地方
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何创建类属性?
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>
- 如何转换列表<字符串>列表<int>?