简体   繁体   English

使用公共字段的最佳做法是什么?

[英]What is the best practice for using public fields?

When I write a class I always expose private fields through a public property like this: 当我写一个类时,我总是通过这样的公共属性公开私有字段:

private int _MyField;
public int MyField
{ get{return _MyField; }

When is it ok to just expose a public field like this: 什么时候可以公开这样的公共字段:

public int MyField;

I am creating a structure called Result and my intention is do this: 我正在创建一个名为Result的结构,我的意图是这样做:

public Result(bool result, string message)
{
   Result = result;
   Message = message;
}

public readonly int Result;
public readonly int Message;

What is the best practice? 什么是最佳做法? Is it ever ok to do this? 这样做好吗?

I only ever expose public fields when they're (static) constants - and even then I'd usually use a property. 当它们是(静态)常量时,我​​只暴露公共字段 - 即便如此,我通常也会使用属性。

By "constant" I mean any readonly, immutable value, not just one which may be expressed as a "const" in C#. “常量”是指任何只读,不可变的值,而不仅仅是可以在C#中表示为“const”的值。

Even readonly instance variables (like Result and Message) should be encapsulated in a property in my view. 甚至readonly 实例变量(如Result和Message)也应该封装在我视图的属性中。

See this article for more details. 有关详细信息,请参阅此文章

What is the best practice for using public fields? 使用公共字段的最佳做法是什么?

“Don't.” See also: Should protected attributes always be banned? “不要。”另请参阅: 是否应始终禁止受保护的属性? which concerns protected fields but what is said there is even more true for public ones. 这涉及到受保护的领域,但对于公共领域来说更是如此。

Use properties. 使用属性。 It's easy now that C# has Automatic Properties ! 现在C#有自动属性很容易!

The best practice is to use properties for several reasons. 最佳做法是使用属性有几个原因。 First, it decouples the API from the underlying data structure. 首先,它将API与底层数据结构分离。 Second, anything built into the framework that binds to objects does to to properties, not fields. 其次,绑定到对象的框架中内置的任何内容都属于属性,而不是字段。

I'm sure there are more reasons, but those two always seem to be enough for me. 我确信有更多的理由,但这两个似乎对我来说似乎已经足够了。

I think best practice is not to do it. 我认为最佳做法不是这样做。 Unless you have some extreme performance need where you must access the field directly don't do it. 除非你有一些极端的性能需求,你必须直接访问该领域,否则不要这样做。

Here is a good article about it: 这是一篇很好的文章:

http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx

I recommend using something similar to this: 我建议使用类似的东西:

public class Result{  
    public bool Result {  get; protected set; }
    public string Message {  get; protected set; }

    public Result(bool result, string message) {
        Result = result;
        Message = message;
    }
}

This way, you don't need to declare member variables, let the compiler do the work for you! 这样,您不需要声明成员变量,让编译器为您完成工作! The code is very clean and short, and refactoring is a breeze. 代码非常干净和简短,重构是轻而易举的。

In C-Style languages (like C#) you should expose fields through properties. 在C风格的语言(如C#)中,您应该通过属性公开字段。 This also pertains to VB.NET and other .NET languages as well as they share the same underlying engine. 这也适用于VB.NET和其他.NET语言,以及它们共享相同的底层引擎。 The main reason to do this is that 这样做的主要原因是

Public MyField as Integer DOES NOT EQUAL Public Property MyField as Integer, They don't have the same behavior in all situation under .NET. 公共MyField作为整数不公共属性MyField作为整数,它们在.NET下的所有情况下都没有相同的行为。

However you will probably see a lot of people continuing to make public Fields. 但是你可能会看到很多人继续公开领域。 Some of this is due to how VB6 handles COM. 其中一些是由于VB6如何处理COM。 In VB6 Public MyField as Integer is equivalent to Public Property MyField as Integer. 在VB6中,Public MyField as Integer等同于Public Property MyField as Integer。 Because when both are translated into a COM typelib they both are implemented in the same way. 因为当它们都被翻译成COM类型库时,它们都以相同的方式实现。

This resulted in a lot of odd restrictions in VB6 over what could be a public field. 这导致了VB6中许多奇怪的限制,而不是公共领域。 Restrictions that are not in .NET and a lot of other Object Oriented languages. 不在.NET和许多其他面向对象语言中的限制。 These restrictions are caught at compile time so prevent a programmer from shooting themselves in the foot so to speak. 这些限制是在编译时捕获的,因此可以防止程序员在脚下射击。 If your class was private in VB6 some of these restriction, but not all, were eased. 如果你的课程在VB6中是私人的,那么这些限制中的一些,但不是全部,都得到了缓解。 The general rule was that you could only expose classes and data types as public fields. 一般规则是您只能将类和数据类型公开为公共字段。

The legacy of VB6 means there are lot of programmers that are not aware that there is a difference in .NET. VB6的遗产意味着有很多程序员不知道.NET存在差异。

Because .NET doesn't help us in this regard then you need to take the tradition step of making sure all fields are exposed through properties. 因为.NET在这方面没有帮助我们,所以你需要采取传统步骤,确保所有字段都通过属性公开。 Again because in .NET a field is not the same as a Property. 再次因为在.NET中,字段与属性不同。

This article (pointed out by others) explains the .NET side of it. 本文 (由其他人指出)解释了它的.NET方面。

I would like to answer on your aproach of readonly. 我想以你的方式回答你的问题。

Readonly isn't a way to have only a get accessor on a public field. Readonly不是在公共字段上只有get访问器的方法。 I mainly use readonly on private field where my private field can only be set from constructor. 我主要在私有字段上使用readonly,我的私有字段只能从构造函数设置。 So to be understand a readonly field can ONLY be set in a contructor and then you can only acess it. 所以要理解一个readonly字段只能在一个构造函数中设置然后你只能访问它。

The best practices is to always use Properties to access your fields after constructor. 最佳实践是始终使用Properties在构造函数之后访问您的字段。 so in case you would have to access your properties from inside your class I would put : 所以万一你必须从课堂内访问你的房产,我会把:

private readonly int result;
private readonly int message;

public Result(bool result, string message)
{
   this.result = result;
   this.message = message;
}

public int Result
{
   get{ return result; }
   private set { result = value; }
}

public int Message
{
   get{ return message; }
   private set { message = value; }
}

That way you can only read Result and Message and can still write to it from inside the class. 这样你只能读取结果和消息,仍然可以从类内部写入。

In case you use inheritance, you could put the set protected if needed. 如果您使用继承,您可以根据需要设置保护集。

EDIT : After reading the code I made based on what was given in the question there is some bug where the Class name Result will probably throw an error with the property Result and also the fact the we are receiving a bool as result and a string as message in constructor but trying to send them in a int this will definatly don't work. 编辑 :在阅读我根据问题中给出的代码后,有一些错误,类名结果可能会抛出属性结果的错误,而且我们收到一个bool作为结果和字符串为在构造函数中的消息,但试图在int中发送它们肯定不起作用。 But for what it's worth here is something mor logic : 但对于它的价值来说,这是一个逻辑:

private readonly bool result;
private readonly string message;

public Answer(bool result, string message)
{
   this.result = result;
   this.message = message;
}

public bool Result
{
   get{ return result; }
   private set { result = value; }
}

public string Message
{
   get{ return message; }
   private set { message = value; }
}

In general, if an type is going to be used as a data holder, it should either be: 通常,如果要将类型用作数据持有者,则它应该是:

  1. A mutable struct with exposed fields, if each of the fields will behave as a value from the standpoint of the type, and any arbitrary combination of field values will "make sense". 具有暴露字段的可变结构,如果每个字段将从类型的立场表现为值,并且任何字段值的任意组合将“有意义”。 Note that the fields holding references to mutable class types may qualify if the purpose of the fields is to hold the identity of the objects in question, rather than the contents. 请注意,如果字段的用途是保存有问题的对象的标识而不是内容,则保留对可变类类型的引用的字段可能有资格。 Structs with mutable fields got a bad reputation as a result of silly C# compilers that would interpret `SomeThing.SomeStruct.SomeField = whatever` as `tempStruct = SomeThing.SomeStruct; 由于愚蠢的C#编译器会将`SomeThing.SomeStruct.SomeField = whatever`解释为`tempStruct = SomeThing.SomeStruct;而带有可变字段的结构声名狼借。 tempStruct.SomeField = whatever` without issuing a diagnostic, but there's no reason for programmers today to worry about such what ancient compilers would do. tempStruct.SomeField = what`而不发布诊断信息,但今天的程序员没有理由担心古代编译器会做什么。
  2. An immutable class or struct with non-public fields, for situations where the above do not apply, and where having to regenerate an entire data item to change one aspect thereof would not be overly bothersome. 具有非公共字段的不可变类或结构,对于上述不适用的情况,以及必须重新生成整个数据项以改变其一个方面的情况,不会过于麻烦。
  3. A mutable class, if references to it will not be persisted outside the entity which creates it (such references should generally never be exposed to outside code). 一个可变类,如果对它的引用不会在创建它的实体之外持久化(这样的引用通常不会暴露给外部代码)。 Note that the other two options, when workable, should be vastly preferred, since a collection which uses a mutable class type as data holder (as opposed to a collection which simply stores the identities of objects but don't care what those objects represent) will often have to make a defensive copy of any object which is stored in the collection, and then make an additional defensive copy every time the object is read. 请注意,其他两个选项,当可行时,应该是非常优选的,因为使用可变类类型作为数据持有者的集合(而不是简单地存储对象的标识但不关心这些对象表示什么的集合)通常必须制作存储在集合中的任何对象的防御性副本,然后在每次读取对象时再制作一个防御性副本。 Structs, whether mutable or "immutable", must be copied whenever they are stored or read back from a collection, but such copies are cheaper, for any size struct , than the defensive copies that would be required if using a mutable class. 无论是可变的还是“不可变的”结构,只要它们从集合中存储或读回,就必须被复制,但对于任何大小的结构 ,这些副本比使用可变类所需的防御副本更便宜。

If there is no practical alternative to using a mutable class, the question of whether to expose public fields depends upon whether there's any foreseeable need for any version of the class to include validation logic in a property setter, and also whether the type of a member will be a value type or class type. 如果没有使用可变类的实际替代方法,是否公开公共字段的问题取决于是否有任何可预见的类需要在属性设置器中包含验证逻辑,以及是否成员类型将是值类型或类类型。 If Bounds is a public field of type Rectangle , an expression like SomeClass.Bounds.Width can access the Width of the rectangle without having to access any other members. 如果BoundsRectangle类型的公共字段,则SomeClass.Bounds.Width之类的表达式可以访问矩形的Width ,而无需访问任何其他成员。 By contrast, if Bounds were a property--even a mutable one--that expression would have to copy all four members of Bounds to a temporary structure, and then access the Width field of that. 相比之下,如果Bounds是一个属性 - 甚至是一个可变属性 - 该表达式必须将Bounds所有四个成员复制到一个临时结构,然后访问它的Width字段。

The answer I give is that Properties are more Refactor friendly. 我给出的答案是属性更加重构友好。

If you have an assembly with read-only fields, then change them to properties. 如果您有一个只读字段的程序集,则将它们更改为属性。 If you have another assembly that I accessing the fields (now properties), they wont work without a compile. 如果你有另一个我访问字段(现在属性)的程序集,它们将无法在没有编译的情况下工作。 Fields and properties are not the same as far as the compiler is concerned. 就编译器而言,字段和属性并不相同。

Back to refactoring, say you started with a property. 回到重构,说你从一个属性开始。 Now you need to change where the data is coming from (you will access it from another class). 现在您需要更改数据的来源(您将从另一个类访问它)。 If you were dealing with fields you have some hard decisions to make on how to make that happen. 如果您正在处理字段,那么您就如何实现这一点做出了一些艰难的决定。 Properties are much more forgiving -- because you can hide logic in them. 属性更宽容 - 因为你可以在其中隐藏逻辑。

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

相关问题 在锁定中使用异步方法的最佳实践是什么 - what is the best practice using async method in lock 从类库中的公共 api 返回数据列表的最佳做法是什么? - What is the best practice to return List of data from public api inside class library? 在Unity的C#中使用静态变量的最佳实践是什么? - What's the best practice to using the static variable in C# of Unity 使用状态模式的分层状态机的最佳实践是什么? - What is the best practice for a hierarchical state machine using the state pattern? 使用Entity Framework实现高级搜索的最佳实践是什么? - What is the best practice to implement advanced search using Entity Framework? 在继承的类中使用锁的最佳实践是什么? - What is the best practice for using lock within inherited classes 使用IEqualityComparer <T>的推荐最佳做法是什么? - What's the recommended best practice for using IEqualityComparer<T>? 使用MVVM模式访问模型的最佳实践是什么 - What is the best practice for accessing Model using MVVM pattern 在MVC 4应用程序中使用Unity with Entity Framework的最佳实践是什么 - What is best practice for using Unity with Entity Framework in a MVC 4 application 使用 switch 语句的最佳实践是什么? 嵌套? 具体的? - What would be the best practice for using switch statements? nested? specific?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM