24

当我编写一个类时,我总是通过这样的公共属性公开私有字段:

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

什么时候可以像这样公开一个公共字段:

public int MyField;

我正在创建一个名为 Result 的结构,我的意图是这样做:

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

public readonly int Result;
public readonly int Message;

最佳做法是什么?这样做可以吗?

4

11 回答 11

32

我只在公共字段是(静态)常量时才公开它们——即使那样我通常也会使用一个属性。

“常量”是指任何只读的、不可变的值,而不仅仅是可以在 C# 中表示为“常量”的值。

在我看来,即使是只读实例变量(如 Result 和 Message)也应该封装在一个属性中。

有关更多详细信息,请参阅本文

于 2008-12-18T20:04:17.493 回答
17

使用公共领域的最佳做法是什么?

“不。” 另请参阅: 是否应始终禁止受保护的属性?这涉及受保护的领域,但所说的对于公共领域来说更是如此。

于 2008-12-18T20:04:04.357 回答
9

使用属性。现在 C# 有自动属性很容易!

于 2008-12-18T20:04:59.753 回答
4

最佳实践是出于多种原因使用属性。首先,它将 API 与底层数据结构分离。其次,任何内置到框架中的绑定到对象的东西都会绑定到属性,而不是字段。

我敢肯定还有更多的原因,但这两个对我来说似乎总是足够的。

于 2008-12-18T20:03:00.193 回答
3

我认为最好的做法是不这样做。除非您有一些极端的性能需求,您必须直接访问该字段,否则不要这样做。

这是一篇关于它的好文章:

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

于 2008-12-18T20:04:35.653 回答
2

我建议使用类似的东西:

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;
    }
}

这样,您无需声明成员变量,让编译器为您完成工作!代码非常干净和简短,重构轻而易举。

于 2008-12-19T05:58:19.340 回答
2

在 C 样式语言(如 C#)中,您应该通过属性公开字段。这也适用于 VB.NET 和其他 .NET 语言,并且它们共享相同的底层引擎。这样做的主要原因是

作为整数的公共 MyField 不等于作为整数的公共属性 MyField,它们在 .NET 下的所有情况下都没有相同的行为。

但是,您可能会看到很多人继续公开 Fields。其中一些是由于 VB6 处理 COM 的方式。在 VB6 Public MyField as Integer 等价于 Public Property MyField as Integer。因为当两者都被翻译成 COM 类型库时,它们都以相同的方式实现。

这导致了 VB6 对可能是公共字段的许多奇怪的限制。.NET 和许多其他面向对象语言中没有的限制。这些限制在编译时就被捕获了,因此可以说防止程序员自爆。如果您的课程在 VB6 中是私有的,那么这些限制中的一些(但不是全部)会被放宽。一般规则是您只能将类和数据类型公开为公共字段。

VB6 的遗留问题意味着很多程序员不知道 .NET 中存在差异。

因为 .NET 在这方面没有帮助我们,所以您需要采取传统步骤,确保所有字段都通过属性公开。再次因为在 .NET 中,字段与属性不同。

这篇文章(由其他人指出)解释了它的 .NET 方面。

于 2008-12-19T13:26:49.740 回答
1

C# 中的字段和属性有什么区别?

于 2008-12-18T20:03:17.730 回答
1

我想回答你的只读方法。

Readonly 不是在公共字段上只有一个 get 访问器的方法。我主要在私有字段上使用只读,我的私有字段只能从构造函数中设置。所以要理解只读字段只能在构造函数中设置,然后你只能访问它。

最佳实践是始终使用属性在构造函数之后访问您的字段。因此,如果您必须从班级内部访问您的属性,我会输入:

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; }
}

这样,您只能读取 Result 和 Message 并且仍然可以从类内部写入。

如果您使用继承,如果需要,您可以将集合设置为受保护的。

编辑:在阅读了我根据问题中给出的内容编写的代码后,存在一些错误,其中类名 Result 可能会抛出属性 Result 的错误,而且我们收到一个 bool 作为结果和一个字符串作为构造函数中的消息,但尝试将它们发送到 int 这肯定行不通。但是这里的价值在于逻辑:

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; }
}
于 2008-12-18T22:54:58.257 回答
0

我给出的答案是属性对重构更友好。

如果您有一个带有只读字段的程序集,则将它们更改为属性。如果您有另一个程序集我访问这些字段(现在是属性),那么它们将无法在没有编译的情况下工作。就编译器而言,字段和属性并不相同。

回到重构,假设你从一个属性开始。现在您需要更改数据的来源(您将从另一个类访问它)。如果您正在处理字段,那么您需要做出一些艰难的决定来决定如何做到这一点。属性更加宽容——因为您可以在其中隐藏逻辑。

于 2008-12-18T23:31:46.560 回答
0

一般来说,如果一个类型将被用作数据持有者,它应该是:

  1. 具有暴露字段的可变结构,如果每个字段从类型的角度来看都将表现为一个值,并且字段值的任意组合将“有意义”。请注意,如果字段的目的是保存相关对象的身份,而不是内容,则保存对可变类类型的引用的字段可能符合条件。由于愚蠢的 C# 编译器会将 `SomeThing.SomeStruct.SomeField = whatever` 解释为 `tempStruct = SomeThing.SomeStruct; tempStruct.SomeField =what` 没有发出诊断,但今天的程序员没有理由担心古代编译器会做什么。
  2. 具有非公共字段的不可变类或结构,适用于上述情况不适用的情况,并且必须重新生成整个数据项以更改其中一个方面不会太麻烦。
  3. 一个可变类,如果对它的引用不会被保存在创建它的实体之外(这种引用通常不应该暴露给外部代码)。请注意,其他两个选项在可行时应该是首选,因为使用可变类类型作为数据持有者的集合(与仅存储对象身份但不关心这些对象代表什么的集合相反)通常必须为存储在集合中的任何对象制作一个防御性副本,然后在每次读取该对象时制作一个额外的防御性副本。结构,无论是可变的还是“不可变的”,在存储或从集合中读回时都必须复制,但是对于任何大小的结构,这样的副本更便宜,而不是使用可变类时所需的防御性副本。

如果没有使用可变类的实际替代方法,是否公开公共字段的问题取决于是否有任何可预见的需要任何版本的类在属性设置器中包含验证逻辑,以及成员的类型是否将是值类型或类类型。如果Bounds是类型的公共字段Rectangle,则表达式 likeSomeClass.Bounds.Width可以访问Width矩形的 ,而无需访问任何其他成员。相比之下,如果Bounds是一个属性——即使是一个可变的——该表达式必须将 的所有四个成员复制Bounds到一个临时结构中,然后访问它的Width字段。

于 2012-07-16T20:09:21.343 回答