检查类型而不是空值是否是一个合理的选择?

5

我的一位(资深)同事在他的代码中做了一些非常奇怪的事情。

他不是检查一个变量是否为null,而是检查它的类型。由于

null是FooType

实际上返回false,所以这个方法是可行的。

public class Foo
{
    private string _bar = null;

    public string Bar
    {
        get
        {
            // strange way to check for null
            return (_bar is string) ? _bar : "";
        }
        set { _bar = value; }
    }
}

我认为这是糟糕的编码,Resharper 似乎也同意我的看法。有没有理由用这种方式进行检查?

这是一种有效的检查变量的方法吗?或者在某些特殊情况下,这可能被认为是不良风格甚至有害的吗?

除非我确定这确实没有意义,否则我不想与他对抗。


1
你的资深同事是否有VB背景? - Seph
我认为是的,至少在VBScript中是常见表达。这在VB中常用吗? - magnattic
旧版本的VB缺乏很多有用的速记运算符,因此以上内容将是速记版本。 - Seph
4个回答

10

这不是一个好的方法。一个更好的方法只是:

return _bar ?? string.Empty;

你在阅读同事的代码时,是否清楚他正在寻找null?如果不清楚,那么这并不是一个好选择。"is"操作符首先会检查null,然后返回false,因此直接自己检查会更加简洁。或者使用null合并运算符。


当你阅读同事的代码时,他是否清楚地表明他正在寻找null值?不是的,但当他检查的变量明显是字符串时,他还能检查什么呢? - magnattic
2
@atticae 这是否使它成为有效的使用方式? - Oskar Kjellin
1
实际上,“is”和“as”背后的IL运算符是相同的,“isinst”,它的作用与“as”非常相似;它检查弹出的引用是否是传递的类标识符的实例,如果是,则推送该实例,否则推送null。 “as”几乎完全使用“isinst”,而“is”还会测试isinst推送的结果是否为null。 - KeithS
1
@KeithS 这使得这种用法在性能方面变得更糟。 - Oskar Kjellin
我刚用ILSpy检查了上面的代码,看起来编译器将其优化为if (this._bar != null) - magnattic
显示剩余5条评论

3

是的,这有点奇怪。为什么不直接写:

return _bar ?? "" ;

当我需要像这样做些事情时,我会有一个小类来处理这些细节:
public class DefaultableValue<T>
{
    private T m_Value = default(T);
    public T Value
    {
        get
        {
            if (IsInvalidPredicate(m_Value))
            {
                m_Value = IfDefaultValueFunc();
            }
            return m_Value;
        }
    }
    private Predicate<T> IsInvalidPredicate { get; set; }
    private Func<T> IfDefaultValueFunc { get; set; }
    public static implicit operator T(DefaultableValue<T> property)
    {
        return property.Value;
    }
    public DefaultableValue(Predicate<T> isInvalidPredicate,Func<T> ifDefaultFunc)
        : this(default(T), isInvalidPredicate, ifDefaultFunc)
    {
    }
    public DefaultableValue(T initValue, Predicate<T> isInvalidPredicate, Func<T> ifDefaultFunc)
    {
        this.m_Value = initValue;
        this.IsInvalidPredicate = isInvalidPredicate;
        this.IfDefaultValueFunc = ifDefaultFunc;
    }
}

然后我的类看起来像这样:

class Test
{
    DefaultableValue<string> AString { get; set; }

    public Test(string initialValue)
    {
        this.AString = new DefaultableValue<string>(initialValue, 
            (value) => string.IsNullOrWhiteSpace(value),
            () => string.Empty);
    }
}

....
var test = new Test(null);
var someString = test.AString; // = "" not null

有太多人从未听说过 ?? - Kendall Frey

3
我觉得这段代码非常令人困惑,我不会使用它。 `_bar` 声明为 `string`,所以这种类型检查只会让人更难理解代码。

0
如果上述公共属性声明为返回object而不是string,那么上述内容可能有意义。但是,因为它返回字符串,这种类型的检查就没有意义了。如果您想返回一个空字符串,可以像这样操作:
public class Foo 
{ 
    private string _bar = null; 

    public string Bar 
    { 
        get 
        {  
            return (String.IsNullOrWhitespace(_bar)) ? "": _bar; 
        } 
        set { _bar = value; } 
    } 
} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接