【问题标题】:Class methods: should I always check variables before accessing them?类方法:我应该在访问变量之前始终检查它们吗?
【发布时间】:2016-07-08 14:28:49
【问题描述】:

抱歉这个愚蠢的问题。

假设我有这个类(代码在 C# 中):

class Foo {
    public List<string> Bars { get; set; }        
    public Foo() { }
}

现在我想实现一个在Bars上执行一些操作的方法,例如Foo.Translate()

我是否应该始终检查我尝试访问/修改的内容是否为空或有效?

class Foo {
    public List<string> Bars { get; set; }        
    public Foo() { }

    public void Translate()
    {
        // Should I check with a null && count > 0?
        if (Bars != null && Bars.Count > 0)
        {
            [...]
        }
    }
}

【问题讨论】:

  • 如果Bars 永远为空,那么你应该在访问它之前检查它是否为空,否则你会得到一个空引用异常。检查它是否非零是业务逻辑..
  • 不,Foo 类的其余部分应确保始终保持不变。
  • Bars 虽然是公开的,但另一个类可以将其设置为 null。
  • 我认为你们对示例中的实现有点过于执着,没有花足够的时间思考实际问题:“我是否应该始终检查我要访问/修改的内容是不为空或有效?”

标签: c# class methods


【解决方案1】:

视情况而定。

如果该值为 null 并且不应该为 null,则显然出现了问题,并且您现在所做的任何事情都是无效的情况,并且无论如何都会给您错误的结果。让它抛出异常。检查日志以找出它为空的原因,并修复该错误。

如果值是 null 是一个有效的场景,那么做你正在做的事情是合适的。

【讨论】:

    【解决方案2】:

    最好在构造函数中验证属性,如果它们无效则抛出异常。 这样,您可以保证每次访问此属性时都应该没问题。 使用私有 setter 设置属性也很好,只有构造函数或自定义方法才能更新您的类属性。

    class Foo {
        public List<string> Bars { get; private set; }        
        public Foo(List<string> bars) 
        { 
            if (bars!= null && bars.Count > 0)
            {
             this.Bars = bars
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      你永远不应该为集合暴露设置器(它会将你的内部暴露给外部并且它违反了封装)。您应该在构造函数中初始化您的集合。这样你就知道它永远不会为空。

      对此有代码分析警告-https://msdn.microsoft.com/en-us/library/ms182327.aspx

      【讨论】:

        【解决方案4】:

        这完全取决于您的期望。如果您希望 Foo 需要 Bars 集合,请让用户在构造函数中传递它并在那里对其进行验证(并将其设为私有)。

        如果您希望 Bar 填充在 Foo 类中,则应确保列表始终在构造函数中实例化(并将其设为私有)。这将避免空检查。

        如果您希望在执行某个操作之前它的计数 > 0,那么您应该在执行该操作之前验证该计数 > 0。

        【讨论】:

          【解决方案5】:

          因为代码中有一个构造函数,所以可以在构造函数中检查一个值是否为空值。通常,如果该值预计不为 null,则可以使用:

          class Foo {
              public List<string> Bars { get; set; }        
              public Foo(string bars) { 
                  try
                  {
                     if(bars == null){ bars = "" } //Whatever value bars should be if null, in this case an empty string.
                  {
                  catch(Exception)
                  {
                     throw;
                  }
          
              }
              public void Translate()
              {
                  // Should I check with a null && count > 0?
                  if (Bars != null && Bars.Count > 0)
                  {
                      [...]
                  }
              }
          }
          

          我相信这会更快,因为当对象 Foo 实例化时,会检查任何空值。

          【讨论】:

            【解决方案6】:

            如果某些东西在正常情况下不应该是null,那么不要检查。让应用程序抛出异常。否则,如果你检查它是null,你会怎么做?您可以将null 替换为其他内容,但该值是否正确?

            但更好的方法是用铁腕控制你的班级状态。如果List&lt;string&gt; Bars 不应该为空,请不要它为空。不允许一个对象将自己置于无效状态,也不允许其他对象将其置于无效状态。如果它不能成为null,那么你不必到处检查。 null 到处检查都是一场瘟疫,表明我们不知道代码的状态是什么。

            最简单的形式:

            class Foo {
                public List<string> Bars { get; } = new List<string>();     
                public Foo() { }
            }
            

            你也可以

            class Foo {
                private readonly List<string> _bars = new List<string>();
                public List<string> Bars { get { return _bars; } }
                public Foo() { }
            }
            

            现在_bars 在创建Foo 时设置为一个新列表,编译器将阻止您更改_bars。您只能修改其内容。现在只要你使用这个类,你就不必担心_bars(或扩展名Bars)是否是null

            返回集合或其他对象的方法也是如此。如果没有什么可返回的,请不要返回null。返回接收方法可以无害地使用的空数组或“空”对象。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-11-12
              • 2021-07-02
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多