Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在C中创建空对象#_C#_Design Patterns_Refactoring - Fatal编程技术网

C# 如何在C中创建空对象#

C# 如何在C中创建空对象#,c#,design-patterns,refactoring,C#,Design Patterns,Refactoring,Martin Fowler的重构讨论了创建空对象以避免大量错误 if (myObject == null) 测试。 正确的方法是什么?我的尝试违反了“构造函数中的虚拟成员调用”规则。 以下是我的尝试: public class Animal { public virtual string Name { get; set; } public virtual string Species { get; set; } public virtual bool IsNull

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

去看看有趣的概念(比如DbNull)所带来的痛苦,想想这是否真的是个好主意

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


Protip II:当出现意外的空值时,让某个东西抛出异常实际上是很好的。如果有不应该为null的null,事情就会变得很糟糕。

null对象模式的要点是它不需要null检查来防止崩溃或错误

例如,如果您试图对Species属性执行操作,但该属性为null,则会导致错误

因此,您不需要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 { ; }
    }
}

只有在合适的情况下,才可以使用此方法。您的动物对象示例可能不是一个好的示例,因为它没有提供使用此方法的适当案例。例如:

Animal animal = new Animal();

if (animal.tail == null)
{
    //do nothing because wagging a tail that doesn't exist may crash the program
}
else
{
    animal.wagTail();
}
在本例中,您应该构建动物对象,这样如果动物没有尾巴,它就可以成功地处理wagTail()命令而不会崩溃

Class Animal
{
    Tail tail;

    void wagTail()
    {
        if (this.tail == null)
        {
            //do nothing
        }
        else
        {
            this.tail.doTheWag();
        }
    }
}
现在,您不需要执行null检查,只需调用animal.wagTail(),而不管动物是否有尾巴。

我倾向于同意,在创建此类“null”对象时,您应该表现出克制。也就是说,这样做有一些很好的理由。偶尔

我也倾向于同意,null对象的全部要点是不需要检查它是否为null,因此您应该丢失IsNull属性。如果您确实觉得需要IsNull属性,那么请再次阅读Wyatt的回复并重新考虑

谢谢你提供更多信息。好东西

现在,我将假设在实际代码中,您实际上有一个构造函数试图设置Name或Species的值(无论您的实际代码等价物可能被调用什么)。否则,为什么会出现“构造函数中的虚拟成员调用”警告/错误?我自己在使用新型的MyProperty{get;set;}快捷方式时遇到了几个类似的问题(特别是在结构中使用时,不要让我开始进行序列化版本控制)。你的解决办法是不使用捷径,而是用老式的方式

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 { }
    }
}
这解决了在构造函数中设置虚拟属性的问题。相反,您正在设置您的私有字段值(如果使用快捷方式,您无法引用这些值)。要获得额外的积分,请编译这两个方法,并使用Reflector查看生成的程序集


我越是使用{get;set;}快捷方式,就越不喜欢它。

我想在这里提到一些有趣的细节。看看你的课。它有什么逻辑吗?这不是一个类,这是一个数据结构。您试图做的是将空对象模式应用于它不适用的对象。数据结构更接近于值类型,而不是类。因此,空检查可以很好地解决您的问题。 空对象模式不是您应该始终遵循的。空对象模式是一种可以用来避免Liskov的替换原则冲突的东西,用来表示一个不做任何事情的类,因为空对象模式不适合替换类,因为它是一个值,而不是一个类。
但在值类型和数据结构方面情况有所不同。空是值!因此,在这种情况下,空检查是正确的做法。

您试图解决的问题是什么?null引用到底有什么问题?NullAnimal类中的IsNull属性应该是重写,而不是虚拟的。但是,如果我们讨论函数,会返回布尔类型吗?我应该返回什么?假的?是吗?我认为这并不明确。另外,在公共财产“物种”中,您返回的值总是空的。。。所以,如果有人做测试,他可能会得到意想不到的结果。例如,有人得到“零动物”的对象,但他认为它是“动物”。因此,他可以假设,如果他将物种设定为“哺乳动物”,他将得到“哺乳动物”。但事实并非如此。它不是那么简单,IMHO+1。Null模式是一种反模式。抛出不需要的Null,并在允许的情况下检查Null。NullObject模式的思想是,事情不会繁荣起来——特别是在producton中。@Wyatt:很好地演示了Null对象的好处……但我个人并不太喜欢它们。@Wyatt这实际上取决于软件,在某些情况下,可能不会使用NullObject模式。我不是恋物癖者——问题是关于空物体。例如,在航空或医疗软件中,应用程序崩溃可能是一件坏事。但在我的动物项目中可能没那么糟糕。它不是某种“反空崇拜”。这样称呼不仅不尊重原始海报,而且在某些情况下,API可以通过宽恕而受益。与DBNull/null进行比较是不准确的,因为DBNull不是从null继承的。因为NullAnimal是一种动物,所以将NullAnimal传递给期待动物的对象不应该引起问题。对于将DBNull传递给期望null的对象,不能这样说。所有这些都表明+1有助于人们思考这是否是个好主意。在大多数情况下,我倾向于同意它不是。很好,但这仍然违反了构造函数中的虚拟成员调用规则。技术上不是,因为没有构造函数。