简体   繁体   English

类方法:在访问变量之前,我应该始终检查变量吗?

[英]Class methods: should I always check variables before accessing them?

Sorry for the stupid question. 很抱歉这个愚蠢的问题。

Let's say I have this class (code is in C#): 假设我有此类(代码在C#中):

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

Now I want to implement a method that perform some operations on Bars , for example Foo.Translate() . 现在,我想实现一种在Bars上执行一些操作的方法,例如Foo.Translate()

Should I always check that what I am trying to access/modify is not null or valid? 我是否应该始终检查要访问/修改的内容是否为null或无效?

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)
        {
            [...]
        }
    }
}

It depends. 这取决于。

If the value is null and it shouldn't be, something has obviously gone wrong and whatever you are doing is now an invalid scenario and going to give you wrong results anyways. 如果该值为null而不应该为null,则显然出现了问题,并且您所做的一切现在都是无效的情况,无论如何都会给您带来错误的结果。 Let it throw the exception. 让它抛出异常。 Check the logs to figure out why it is null, and fix that error. 检查日志以找出为什么它为空,然后修复该错误。

If it is a valid scenario for the value to be null, it would be appropriate to do what you are doing. 如果将值设为null是有效的方案,则应该执行您正在做的事情。

It good practice to validate properties in your constructor and if they are not valid to throw an Exception. 优良作法是在构造函数中验证属性,如果属性无效则抛出Exception。 That way you can guarantee that every time you will access this property it should be ok. 这样,您可以保证每次访问此属性都可以。 And it's also good o set the property with private setter this way only the constructor or a custom method can update your class properties. 同样,用私有设置器设置属性也很好,这样只有构造函数或自定义方法可以更新您的类属性。

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

You should never expose setters for collections (It is exposing your internals to outside and it violates encapsulation). 您永远不应该公开集合的setter(它将内部结构暴露于外部,并且违反了封装)。 You should initialize your collection in the constructor. 您应该在构造函数中初始化您的集合。 That way you know it will never be null. 这样,您就知道它永远不会为空。

There is a code analysis warning for this - https://msdn.microsoft.com/en-us/library/ms182327.aspx 为此有一个代码分析警告-https://msdn.microsoft.com/zh-cn/library/ms182327.aspx

It's all about your expectations. 这都是关于您的期望。 If you expect Foo to require a Bars collection, make the user pass it in the constructor and validate it there (and make it private). 如果您期望Foo需要Bars集合,请让用户在构造函数中传递它,并在其中进行验证(并将其私有)。

If you expect Bar to be populated within the Foo class, you should ensure that the list is always instantiated in the constructor (and make it private). 如果希望Bar在Foo类中填充,则应确保始终在构造函数中实例化该列表(并将其设为私有)。 That will avoid null checks. 这样可以避免空检查。

If you expect it to have a count > 0 before performing some operation, then, as you have, you should verify that count > 0 before performing that operation. 如果您希望它在执行某些操作之前计数> 0,则应像执行操作一样,先验证count> 0。

Because there is a constructor in the code, a value can be checked within the constructor for null values. 因为代码中有一个构造函数,所以可以在构造函数中检查一个值是否为空值。 Typically, if the value is expected to not be null this could be used: 通常,如果期望该值不为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)
        {
            [...]
        }
    }
}

I believe this is faster, as when the object Foo instantiated, any null values are checked. 我相信这样会更快,因为当实例化对象Foo时,将检查所有空值。

If something shouldn't ever be null under normal circumstances then don't check. 如果在正常情况下某些东西永远不应该为null ,则不要检查。 Let the application throw an exception. 让应用程序引发异常。 Otherwise if you do check and it is null , what are you going to do? 否则,如果您检查并且它为null ,您将要做什么? You could replace the null with something else, but is that value correct? 您可以将null替换为其他值,但是该值正确吗?

But the better approach is to control the state of your classes with an iron fist. 但是更好的方法是用铁拳控制班级状态。 If List<string> Bars shouldn't be null, don't let it be null. 如果List<string> Bars不应为null,不让它为空。 Don't allow an object to place itself in an invalid state, and don't allow other objects to put it in an invalid state. 不允许对象将自己置于无效状态,也不允许其他对象将其置于无效状态。 If it can't be null then you don't have to check everywhere. 如果不能 null则不必检查所有位置。 null checks everywhere are a plague, and a sign that we don't know what the state of our code is. null检查到处都是困扰,这是一个我们不知道代码状态是什么的信号。

In its simplest form: 最简单的形式:

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

You could also do 你也可以

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

Now _bars is set to a new List when Foo is created and the compiler will prevent you from ever changing _bars . 现在,在创建Foo时,将_bars设置为新列表,并且编译器将阻止您更改_bars You can only modify its contents. 您只能修改其内容。 Now for as long as you work with this class you've removed ever having to worry about whether _bars (or by extension Bars ) is null . 现在,只要您使用该类,就不必担心_bars (或扩展名为Bars )是否为null

The same goes for methods that return collections or other objects. 返回集合或其他对象的方法也是如此。 If there's nothing to return, don't return null . 如果没有返回null ,请不要返回null Return an empty array or an "empty" object that the receiving method can work with harmlessly. 返回一个空数组或一个“空”对象,接收方法可以无害地使用该对象。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM