如何在C#中创建Null对象

Sis*_*utl 12 c# refactoring design-patterns

Martin Fowler的Refactoring讨论了创建Null对象以避免大量的问题

if (myObject == null)
Run Code Online (Sandbox Code Playgroud)

试验.这样做的正确方法是什么?我的尝试违反了"构造函数中的虚拟成员调用"规则.这是我的尝试:

public class Animal
{
    public virtual string Name { get; set; }
    public virtual string Species { get; set; }
    public virtual bool IsNull 
    { 
        get { return false; }
    }
}

public sealed class NullAnimal : Animal
{
    public override string Name
    {
        get{ return "NULL"; }
        set { }
    }
    public override string Species
    {
        get { return "NULL"; }
        set { }
    }
    public virtual bool IsNull
    {
        get { return true; }
    }
}
Run Code Online (Sandbox Code Playgroud)

Wya*_*ett 25

去查看有趣概念(例如DbNull)引起的痛苦程度,并考虑这是否真的是一个好主意.

Protip:如果你经常检查空引用,你可能应该重新考虑一下API,以帮助排除靠近堆栈顶部的空对象.

Protip II:当出现意外的null时,抛出异常实际上是好的和花花公子.如果你的空值不应该为空,那么事情应该会好转.

  • +1.Null模式是一种反模式的IMO.抛出不需要的空值并在允许时检查空值. (8认同)
  • 这不是某种"反无神论".称它不仅不尊重原始海报,而且在某些情况下,API可以通过原谅而受益.与DBNull/null相比,不准确,因为DBNull不从null继承.由于NullAnimal是一个Animal,将NullAnimal传递给期望Animal的东西不应该导致问题.关于将DBNull传递给期望为null的东西的东西你不能说.所有这一切都说+1提示想一想这是不是一个好主意.在大多数情况下,我倾向于同意它不是. (6认同)
  • NullObject 模式的想法是事情不会变得繁荣——尤其是在生产中。 (2认同)
  • @Wyatt这取决于软件,在某些情况下,也许你不会使用NullObject模式.我不是恋物癖者 - 问题是关于NullObjects.例如,在航空或医疗软件中 - 应用程序崩溃可能是一件坏事.但在我的动物项目中可能并不那么糟糕. (2认同)

Pau*_*per 11

我倾向于同意Wyatt Barnett的回答,因为在创建这些"空"对象时你应该表现出克制.也就是说,有一些很好的理由这样做.不定期的.

我也倾向于同意Supertux的答案,因为null对象的重点是不需要检查它是否为null,所以你应该丢失IsNull属性.如果你真的觉得你需要IsNull属性,那么再次阅读Wyatt的回复并重新考虑.

感谢CraigTP提供更多信息的好链接.好东西.

现在我将假设在您的实际代码中,您实际上有一个构造函数正在尝试设置Name或Species的值(无论您的实际代码等价物是否可能被调用).否则,为什么你会得到"构造函数中的虚拟成员调用"警告/错误?当使用新奇的MyProperty时,我遇到了几个类似的问题{get; 组; 我自己的快捷方式(特别是在结构中使用时,并没有让我开始关于序列化版本控制).您的解决方案是不使用快捷方式,而是以老式的方式进行.

public class Animal {
    protected Animal() { }

    public Animal(string name, string species) {
        _Name = name;
        _Species = species;
    }

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

    public virtual string Species {
        get { return _Species; }
        set { _Species = value; }
    }
    private string _Species;
}

public sealed class NullAnimal : Animal {
    public override string Name {
        get { return String.Empty; }
        set { }
    }
    public override string Species {
        get { return String.Empty; }
        set { }
    }
}
Run Code Online (Sandbox Code Playgroud)

这解决了在构造函数中设置虚拟属性的问题.相反,您正在设置私有字段值(如果使用快捷方式,则无法引用该字段值).要获得额外的功劳,请编译这两种方法,并使用Reflector查看生成的程序集.

我越用{get; 组; }捷径,我越不喜欢它.