如何在 C# 中创建空对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1178399/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I create a Null Object in C#
提问by Sisiutl
Martin Fowler's Refactoring discusses creating Null Objects to avoid lots of
Martin Fowler 的重构讨论了创建空对象以避免大量
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; }
}
}
采纳答案by Paul Hooper
I tend to agree with Wyatt Barnett's answerin that you should show restraint when creating these kinds of "null" objects. That said, there are some nice reasons for doing so. On occasion.
我倾向于同意Wyatt Barnett 的回答,因为在创建这些类型的“空”对象时应该表现出克制。也就是说,这样做有一些很好的理由。不定期的。
I also tend to agree with Supertux's answerin 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.
我也倾向于同意Supertux 的回答,因为空对象的全部意义在于不需要检查它是否为空,因此您应该丢失 IsNull 属性。如果您真的觉得需要 IsNull 属性,请再次阅读 Wyatt 的回复并重新考虑。
And thank you CraigTP for the nice linksfor more info. Good stuff.
并感谢CraigTP 提供有关更多信息的好链接。好东西。
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.
现在我假设在你的真实代码中你实际上有一个构造函数试图设置 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 { }
}
}
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.
我越用 { get; 放; } 捷径,我越不喜欢它。
回答by Wyatt Barnett
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.
去查看有趣的概念(例如 DbNull)造成的痛苦程度,并考虑这是否真的是一个好主意。
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.
提示:如果您经常检查空引用,您可能应该重新考虑 API 以帮助排除更接近堆栈顶部的空对象。
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.
Protip II:当出现意外空值时抛出异常实际上很好而且很花哨。如果您有不应该为空的空值,事情应该会变得繁荣。
回答by Supertux
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.
例如,如果您尝试对 Species 属性执行操作并且它为 null - 它会导致错误。
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.:
因此,您不需要 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 { ; }
}
}
回答by tyriker
You only use this approach if it is appropriate. Your example of an Animal object might not be a good example because it doesn't present an appropriate case where you would use this approach. For example:
只有在合适的情况下才使用这种方法。您的 Animal 对象示例可能不是一个很好的示例,因为它不提供您使用此方法的适当情况。例如:
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();
}
In this example, you should build the Animal object so that if the animal doesn't have a tail, it can successfully handle the wagTail() command without crashing.
在此示例中,您应该构建 Animal 对象,以便如果动物没有尾巴,它可以成功处理 wagTail() 命令而不会崩溃。
Class Animal
{
Tail tail;
void wagTail()
{
if (this.tail == null)
{
//do nothing
}
else
{
this.tail.doTheWag();
}
}
}
Now you don't need to do a null check, but can just call animal.wagTail() regardless of whether the animal has a tail or not.
现在你不需要做空检查,而是可以调用 animal.wagTail() 而不管动物是否有尾巴。
回答by Alexey
I'd like to mention here some interesting detail. Look at your class. Does it has any logic in it? This is not a class in its sense, this is a data structure. What you are trying to do is apply null object pattern to something it is not applicable to. Data structures is closer to value types, than to classes. There fore null check can be right in place to solve your problem. Null object pattern is not something you should always follow. Null object pattern is a thing you can use to avoid Liskov's substitution principle violation, to represent a class that does nothing, because null is not appropriate substitution for a class as it is a value, but not a class. But things are different with value types and data structures. Null is value! So in this case null check is the right thing to do.
我想在这里提到一些有趣的细节。看看你的课。它有什么逻辑吗?这不是一个意义上的类,这是一个数据结构。您要做的是将空对象模式应用于它不适用的东西。数据结构更接近于值类型,而不是类。因此,空检查可以正确地解决您的问题。空对象模式不是您应该始终遵循的。空对象模式是一种可以用来避免违反 Liskov 替换原则的东西,用来表示一个什么都不做的类,因为 null 不是一个类的适当替换,因为它是一个值,而不是一个类。但是值类型和数据结构不同。Null 是值!所以在这种情况下,空检查是正确的做法。