代码之家  ›  专栏  ›  技术社区  ›  Sisiutl

如何在C中创建空对象#

  •  12
  • Sisiutl  · 技术社区  · 17 年前

    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; }
        }
    }
    
    5 回复  |  直到 11 年前
        1
  •  26
  •   Wyatt Barnett    17 年前

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

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

        2
  •  11
  •   Community Mohan Dere    9 年前

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

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

    CraigTP for the nice links 更多信息。好东西。

    现在,我将假设在实际代码中,您实际上有一个构造函数试图设置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;}快捷方式,就越不喜欢它。

        3
  •  3
  •   Supertux    17 年前

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

    例如,如果您试图对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 { ; }
        }
    }
    
        4
  •  2
  •   Dour High Arch    17 年前

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

        5
  •  0
  •   Alexey    12 年前

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