如何在C#中创建一个Null对象[英] How do I create a Null Object in C#

本文是小编为大家收集整理的关于如何在C#中创建一个Null对象的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

马丁·福勒(Martin Fowler)的重构讨论创建空对象以避免大量

if (myObject == null)

测试. 正确的方法是什么?我的尝试违反了"构造函数中的虚拟会员呼叫"规则. 这是我的尝试:

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; }
    }
}

推荐答案

我倾向于同意怀亚特·巴内特(Wyatt Barnett)的答案因为在创建此类" null"对象时,您应该表现出约束.也就是说,这样做有一些很好的理由.有时.

我也倾向于同意 supertux's答案因为无效对象的全部要点是不需要检查它是否为null,因此您应该丢失Isnull属性.如果您真的觉得自己需要Isnull属性,请再次阅读Wyatt的回复并重新考虑.

谢谢 craigtp链接有关更多信息.好东西.

现在,我将假设在您的真实代码中,您实际上有一个试图设置名称或物种值的构造函数(无论您可以调用实际代码等效的内容).否则,为什么要获得"构造函数中的虚拟会员调用"警告/错误?当使用newfangled 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 { }
    }
}

这解决了在构造函数中设置虚拟属性的问题.相反,您正在设置私有字段值(如果您使用快捷方式,则无法参考).要获得额外的信用,请编译这两种方法,并使用反射器来查看最终的组件.

我越多地使用{get;放; }快捷方式,我越喜欢它.

其他推荐答案

去查找有趣的概念(例如dbnull)引起并思考这是否真的是个好主意的痛苦的程度.

protip:如果您不断检查无效引用,则可能应该重新考虑API以帮助排除零件靠近堆栈顶部.

PROTIP II:当出乎意料的空实际上是好且花花公子时,有东西会抛出异常.如果您的零是不应该有空的,那么事情应该繁荣.

其他推荐答案

空对象模式的点是它不需要零检查以防止崩溃或错误.

例如,如果您尝试在物种属性上执行操作,但这将导致错误.

因此,您不需要iSnull方法,只需返回Getter中的某些内容,即不会导致应用程序崩溃/错误,例如:

public class Animal
{
    public virtual string Name { get; set; }
    public virtual string Species { get; set; }
}

public sealed class NullAnimal : Animal
{
    public override string Name
    {
        get{ return string.Empty; }
        set { ; }
    }
    public override string Species
    {
        get { return string.Empty; }
        set { ; }
    }
}

本文地址:https://www.itbaoku.cn/post/627787.html

问题描述

Martin Fowler's Refactoring discusses creating Null Objects to avoid lots of

if (myObject == null)

tests. What is the right way to do this? My attempt violates the "virtual member call in constructor" rule. Here's my attempt at it:

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; }
    }
}

推荐答案

I tend to agree with Wyatt Barnett's answer in that you should show restraint when creating these kinds of "null" objects. That said, there are some nice reasons for doing so. On occasion.

I also tend to agree with Supertux's answer in that the whole point of a null object is to not need to check whether or not it is null, so you should lose the IsNull property. If you really feel you need the IsNull property, then read Wyatt's response again and reconsider.

And thank you CraigTP for the nice links for more info. Good stuff.

Now I will assume that in your real code you actually have a constructor that is attempting to set the values of Name or Species (whatever your real code equivalent might be called). Otherwise, why would you get the "virtual member call in constructor" warning/error? I've run into a couple of similar problems when using the newfangled MyProperty { get; set; } shortcut myself (particularly when used in structs, and don't get me started about serialization versioning). Your solution is to not use the shortcut, but instead do it the old-fashioned way.

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 { }
    }
}

This solves the problem of setting your virtual properties in the constructor. Instead, you are setting your private field values (something you don't have the ability to reference if you use the shortcut). For extra credit, compile both methods, and use the Reflector to look at the resulting assemblies.

The more I use the { get; set; } shortcut, the more I dislike it.

其他推荐答案

Go look up the amount of pain that interesting concepts, such as DbNull, have caused and think about if this is actually a good idea.

Protip: if you are constantly checking for null references, you probably should rethink the API a bit to help preclude null objects closer to the top of the stack.

Protip II: having something throw an exception when there is an unexpected null is actually fine and dandy. Things should go boom if you have nulls where there shouldn't be null.

其他推荐答案

The point of the Null Object pattern is that it doesn't require a null check to prevent a crash or error.

For example if you tried to perform an operation on the Species property and it was null - it would cause an error.

So, you shouldn't need an isNull method, just return something in the getter that won't cause the app to crash/error e.g.:

public class Animal
{
    public virtual string Name { get; set; }
    public virtual string Species { get; set; }
}

public sealed class NullAnimal : Animal
{
    public override string Name
    {
        get{ return string.Empty; }
        set { ; }
    }
    public override string Species
    {
        get { return string.Empty; }
        set { ; }
    }
}