【问题标题】:Blocking access to private member variables? Force use of public properties?阻止访问私有成员变量?强制使用公共财产?
【发布时间】:2010-07-16 14:03:35
【问题描述】:

我使用的是 .NET 2.0,因此无法访问自动属性。所以我必须求助于以下编码私有变量和公共属性的方式

private string m_hello = null;

public string Hello
{
     get{return m_hello;}
     set{m_hello = value;}
}

对于上述私有/公共成员的包含类的方法,是否有限制对私有变量的访问?我不喜欢这样,我可以使用 m_hello 或 Hello。

谢谢。

【问题讨论】:

  • 需要注意的一点 - 即使您的目标是 .NET 2.0,如果您使用 C# 3 来执行此操作,您仍然可以使用自动属性。它们不需要任何框架支持。
  • @Jon -- 这可能是足够重要的信息来保证答案而不是评论。
  • @tvanfosson -- 我同意,对此一无所知!
  • 不是很相关,但我很惊讶人们仍在使用“m_”。它不仅被推荐反对(我个人更喜欢用前导的“_”来表示私有变量),它也很丑陋,尽管这可能是个人意见。这是一篇关于 .NET 命名约定和编程标准的文章:10rem.net/articles/…
  • 我在这里问了一个类似的问题:stackoverflow.com/questions/3161401/…

标签: c# oop


【解决方案1】:

正如其他人所建议的那样,这应该是一个答案......

当面向 .NET 2.0 时,您仍然可以在 C# 3 中使用自动属性以及 quite a few other C# 3 features。与(比如说)表达式树不同,除了[CompilerGenerated] 属性(在 .NET 2.0 中引入)之外,自动属性不需要 CLR 或框架中的任何特殊内容。

因此,如果您使用的是 VS2008 或 VS2010,那么值得使用自动属性。

尽管如此,我也想要这个能力。我希望能够在属性中限定变量:

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

我认为这有点像将私有变量设为只读 - 它对客户端没有影响,但有助于在类代码本身内强制执行正确性。

【讨论】:

  • +1 - 我完全同意私有作用域的属性变量。我真的很希望能够在属性方法中拥有任意代码 限制对属性的支持字段的访问,这样我就不会意外地避免 getter/ 中的“规则”设置器代码。
  • 切向相关,我也想要不可变的自动属性(可通过构造函数或初始化语法设置),然后只能从那里获取。由编译器生成的readonly 字段支持。
【解决方案2】:

您可以通过继承来完成此操作:

abstract class A // A is not instantiatable due to being abstract
{
    private string m_hello = null;

    public string Hello
    {
         get{return m_hello;}
         set{m_hello = value;}
    }
}

class B : A
{
    // B now cannot access the private variable, use B in your code instead of A
}

我并不是说这很好。只是可以做到。

【讨论】:

    【解决方案3】:

    不,没有办法做到这一点,除了简单地遵循你自己的约定并这样做。你好,如果你真的需要通过你的公共财产。

    我也不明白你为什么需要/想要这样做,因为它是你的内部类,你是控制代码的人,你可以定义它的使用/如何使用,所以应该不是问题。

    【讨论】:

    • 哇!抱歉@Mitchel - 我不小心编辑了错误的帖子。对不起。
    • @Marc - 你是否被可爱的随机排序功能所吸引?我不止一次发生过这种情况,我自动假设我的问题在编辑(或提交)后处于同一位置并盲目地单击编辑按钮。当该位置的答案以几乎相同的文本开头时无济于事。
    【解决方案4】:

    没有。类中的任何方法都可以访问两者。

    您的团队应该标准化使用哪个(属性或私有变量)。

    一旦您决定使用哪个,您可以尝试使用自定义 FxCop 规则来执行该标准。

    【讨论】:

      【解决方案5】:

      不,基本上。好吧,您可以通过[Obsolete]#pragma 对编译器警告做一些事情,但这太过分了。

      您可以可能使用工具来做到这一点,但最终您需要相信人们不会做愚蠢的事情。毕竟,您是否有关于以下方面的特殊规定:

      while(true) { }
      

      或者你只是把它归结为“不要愚蠢”? ;p

      【讨论】:

      • while(true) 加上循环体内的break 是一个完全有效的编程结构。还有比这更糟糕的事情。
      • @ToxicAvenger - 但没有 break?
      • 任何事情都可以通过这种推理来证明。
      【解决方案6】:

      您只能通过公共 Hello 属性访问该属性。这就是这种模式的原因。如果您向 get 或 set 添加任何功能,如果您正在访问私有实例,您将在代码中引入错误。但是答案是否定的,您不能阻止某人在您的班级内更改您的代码时调用 Private。

      【讨论】:

      • 可以说,它可以双向:您可能希望直接引用支持字段,这样您就不会受到任何添加到公共属性的影响。然而,在这一点上保持一致是一个好主意,并且可能是一个好主意,清楚地识别支持变量,很明显一个属性被绕过了。例如,您可以为它们加上 _Prop 或类似的后缀。
      • 我更喜欢一致性,只是想指出这种模式的原因。每个解决方案总是有原因的,但这并不是最佳实践。
      【解决方案7】:

      就个人而言,我认为访问类中的私有成员没有任何问题。事实上,这就是我通常会做的事情(除非属性 getter/setter 中有我一直想要利用的逻辑)。

      这对我来说很有意义:类中的代码构成该类的实现;为什么要对自己隐藏一个实现?

      这是我的意思的一个例子。假设我有一些成员 m_denominator,我希望它永远不会为零:

      private int m_denominator = 1;
      public int Denominator
      {
          get { return m_denominator; }
          set
          {
              if (value == 0)
                  throw new ArgumentException("Denominator must not be zero.");
              m_denominator = value;
          }
      }
      

      我可能会对自己说:“好吧,我在这个类中设置这个值的任何地方,我都应该使用Denominator 来确保我没有将它设置为零。” 但我完全可以控制我将 Denominator 设置为的内容——我在课堂上!这个场景中,逻辑的重点是Denominator 属性是为了保护类免受客户端代码设置的无效值的影响。没有任何借口可以在类本身的实现中将您的内部状态设置为某个无效值。

      当然,这不是一个绝对的规则。有时,在类中使用属​​性作为其逻辑可能是一种明智的选择作为保护措施;真的,我只是认为从类中访问私有成员没有错

      【讨论】:

      • 那么当你在 6 个月后回到代码中向属性设置器添加重要逻辑时会发生什么?您所有班级的内部代码现在都将绕过新的实现。
      • 我更喜欢默认使用该属性,因为我不想跟踪该属性有什么特殊用途的地方。优化器通常会负责优化方法调用,至少对于简单的访问器是这样。只有当我知道该属性做了一些“特殊”的事情并且我想避免出于某些特定目的时,我才会使用该属性。
      • @Dr Herbie:但根据我的经验,您可能会向属性添加逻辑,但不会希望在每次访问发生时都执行该逻辑在类内——仅对来自外部代码的访问。我确实与向他们的属性添加逻辑的开发人员合作过,他们突然发现他们的一些代码执行的频率比他们预期的要高。显然,这是一个判断电话。我只是指出,向外界隐藏你的实现和向......隐藏它本身是有区别的。
      • 我发现这种推理非常可疑。通常,您将额外的代码放入属性设置器中以强制执行某些依赖项或业务规则。我的经验是,您通常不想想要避免这种情况,即使在课堂上也是如此。当然也有例外——在这些情况下我会引用支持属性——但因为它们是例外的,所以我在默认情况下使用该属性,而不是相反。参考您的示例,我会说在初始化程序中直接使用该字段很好,但是在您的类中的其他任何地方,您确实想使用该属性
      • @tvanfosson:嘿,我不是说你错了。我的观点基本上是这样的:OP 似乎正在寻找一种方法来禁止从实现中访问私有成员。我是说:这不是您需要做的必要。至于什么样的逻辑应该或不应该进入属性 getter/setter,这是一个不同的论点。无论如何,我们似乎都愿意承认有时一种方法是合理的,而有时另一种方法更有意义;这就是我真正想要争论的全部——不是哪一个是例外,哪一个是规则。
      【解决方案8】:

      如果您发现自己想对自己隐藏详细信息,那可能是您的班级有太多职责的代码味道。考虑将其中一项职责提取到一个新类中。

      【讨论】:

      • 有时不是“你自己”,而是团队中的其他成员无法遵守规则。我知道,理论上一切都有一个简单的解决方案,但生活很艰难......
      • @JoeWhite:这是一个有趣的观点。然而,将课程分散到每个人几乎承担微不足道的责任的程度在理论上听起来不错,但在实践中,就其本身的理解而言可能是一场噩梦。
      【解决方案9】:

      我相信C#10,或者至少是proposal,你可以使用半自动属性。

      我们现在可以使用 field 关键字代替支持属性字段。

      所以这个:

      private int _theNumber;
      public int TheNumber 
      {
          get => _theNumber;
          set => _theNumber = value;
      }
      

      变成这样:

      public int TheNumber
      {
          get => field;
          set => field = value;
      }
      

      在示例中,我提供了一个自动属性会更有意义,但我想展示一个简单的示例。

      【讨论】:

        猜你喜欢
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-04
        • 2018-05-18
        • 1970-01-01
        • 2016-06-06
        • 1970-01-01
        相关资源
        最近更新 更多