在 C# 中进行空检查的更简洁方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17672481/
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
Cleaner way to do a null check in C#?
提问by now he who must not be named.
Suppose, I have this interface,
假设,我有这个界面,
interface IContact
{
IAddress address { get; set; }
}
interface IAddress
{
string city { get; set; }
}
class Person : IPerson
{
public IContact contact { get; set; }
}
class test
{
private test()
{
var person = new Person();
if (person.contact.address.city != null)
{
//this will never work if contact is itself null?
}
}
}
Person.Contact.Address.City != null
(This works to check if City is null or not.)
Person.Contact.Address.City != null
(这用于检查 City 是否为空。)
However, this check fails if Address or Contact or Person itself is null.
但是,如果地址或联系人或人员本身为空,则此检查将失败。
Currently, one solution I could think of was this:
目前,我能想到的一种解决方案是:
if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null)
{
// Do some stuff here..
}
Is there a cleaner way of doing this?
有没有更干净的方法来做到这一点?
I really don't like the null
check being done as (something == null)
. Instead, is there another nice way to do something like the something.IsNull()
method?
我真的不喜欢null
像(something == null)
. 相反,有没有另一种很好的方法来做类似something.IsNull()
方法的事情?
采纳答案by Toto
In a generic way, you may use an expression tree and check with an extension method:
通常,您可以使用表达式树并使用扩展方法进行检查:
if (!person.IsNull(p => p.contact.address.city))
{
//Nothing is null
}
Full code:
完整代码:
public class IsNullVisitor : ExpressionVisitor
{
public bool IsNull { get; private set; }
public object CurrentObject { get; set; }
protected override Expression VisitMember(MemberExpression node)
{
base.VisitMember(node);
if (CheckNull())
{
return node;
}
var member = (PropertyInfo)node.Member;
CurrentObject = member.GetValue(CurrentObject,null);
CheckNull();
return node;
}
private bool CheckNull()
{
if (CurrentObject == null)
{
IsNull = true;
}
return IsNull;
}
}
public static class Helper
{
public static bool IsNull<T>(this T root,Expression<Func<T, object>> getter)
{
var visitor = new IsNullVisitor();
visitor.CurrentObject = root;
visitor.Visit(getter);
return visitor.IsNull;
}
}
class Program
{
static void Main(string[] args)
{
Person nullPerson = null;
var isNull_0 = nullPerson.IsNull(p => p.contact.address.city);
var isNull_1 = new Person().IsNull(p => p.contact.address.city);
var isNull_2 = new Person { contact = new Contact() }.IsNull(p => p.contact.address.city);
var isNull_3 = new Person { contact = new Contact { address = new Address() } }.IsNull(p => p.contact.address.city);
var notnull = new Person { contact = new Contact { address = new Address { city = "LONDON" } } }.IsNull(p => p.contact.address.city);
}
}
回答by MarcinJuraszek
The second question,
第二个问题,
I really don't like the null check being done as (something == null). Instead, is there another nice way to do something like the something.IsNull() method?
我真的不喜欢将 null 检查作为 (something == null) 进行。相反,是否有另一种不错的方法来执行 something.IsNull() 方法之类的操作?
could be solved using an extension method:
可以使用扩展方法解决:
public static class Extensions
{
public static bool IsNull<T>(this T source) where T : class
{
return source == null;
}
}
回答by Vladimir Gondarev
You can write:
你可以写:
public static class Extensions
{
public static bool IsNull(this object obj)
{
return obj == null;
}
}
and then:
进而:
string s = null;
if(s.IsNull())
{
}
Sometimes this makes sense. But personally I would avoid such things... because this is is not clear why you can call a method of the object that is actually null.
有时这是有道理的。但我个人会避免这样的事情......因为这不清楚为什么你可以调用一个实际上为空的对象的方法。
回答by Ashok Damani
Do it in a separate method
like:
做一个单独的method
像:
private test()
{
var person = new Person();
if (!IsNull(person))
{
// Proceed
........
Where your IsNull
method
is
当你的IsNull
method
就是
public bool IsNull(Person person)
{
if(Person != null &&
Person.Contact != null &&
Person.Contact.Address != null &&
Person.Contact.Address.City != null)
return false;
return true;
}
回答by Koryu
in your case you could create a property for person
在您的情况下,您可以为 person 创建一个属性
public bool HasCity
{
get
{
return (this.Contact!=null && this.Contact.Address!= null && this.Contact.Address.City != null);
}
}
but you still have to check if person is null
但你仍然需要检查 person 是否为空
if (person != null && person.HasCity)
{
}
to your other question, for strings you can also check if null or empty this way:
对于您的另一个问题,对于字符串,您还可以通过这种方式检查是否为 null 或为空:
string s = string.Empty;
if (!string.IsNullOrEmpty(s))
{
// string is not null and not empty
}
if (!string.IsNullOrWhiteSpace(s))
{
// string is not null, not empty and not contains only white spaces
}
回答by Adam Houldsworth
Update 28/04/2014:Null propagation is planned for C# vNext
2014 年 4 月 28 日更新:计划为 C# vNext 进行空传播
There are bigger problems than propagating null checks. Aim for readablecode that can be understoodby another developer, and although it's wordy - your example is fine.
有比传播空检查更大的问题。目标是其他开发人员可以理解的可读代码,虽然它很罗嗦 - 你的例子很好。
If it is a check that is done frequently, consider encapsulating it inside the Person
class as a property or method call.
如果是经常进行的检查,可以考虑将其封装在Person
类中作为属性或方法调用。
That said, gratuitous Func
and generics!
也就是说,无偿Func
和泛型!
I would never do this, but here is another alternative:
我永远不会这样做,但这是另一种选择:
class NullHelper
{
public static bool ChainNotNull<TFirst, TSecond, TThird, TFourth>(TFirst item1, Func<TFirst, TSecond> getItem2, Func<TSecond, TThird> getItem3, Func<TThird, TFourth> getItem4)
{
if (item1 == null)
return false;
var item2 = getItem2(item1);
if (item2 == null)
return false;
var item3 = getItem3(item2);
if (item3 == null)
return false;
var item4 = getItem4(item3);
if (item4 == null)
return false;
return true;
}
}
Called:
调用:
static void Main(string[] args)
{
Person person = new Person { Address = new Address { PostCode = new Postcode { Value = "" } } };
if (NullHelper.ChainNotNull(person, p => p.Address, a => a.PostCode, p => p.Value))
{
Console.WriteLine("Not null");
}
else
{
Console.WriteLine("null");
}
Console.ReadLine();
}
回答by Microtechie
In my opinion, the equality operator is not a safer and better wayfor reference equality.
在我看来,相等运算符并不是引用相等的更安全和更好的方法。
It's always better to use ReferenceEquals(obj, null)
. This will always work. On the other hand, the equality operator (==) could be overloaded and might be checking if the values are equal instead of the references, so I will say ReferenceEquals()
is a safer and better way.
使用ReferenceEquals(obj, null)
. 这将始终有效。另一方面,相等运算符 (==) 可能会被重载,并且可能会检查值是否相等而不是引用,所以我会说这ReferenceEquals()
是一种更安全更好的方法。
class MyClass {
static void Main() {
object o = null;
object p = null;
object q = new Object();
Console.WriteLine(Object.ReferenceEquals(o, p));
p = q;
Console.WriteLine(Object.ReferenceEquals(p, q));
Console.WriteLine(Object.ReferenceEquals(o, p));
}
}
Reference: MSDN article Object.ReferenceEquals Method.
参考:MSDN 文章Object.ReferenceEquals 方法。
But also here are my thoughts for null values
但这里也是我对空值的想法
Generally, returning null values is the best idea if anyone is trying to indicate that there is no data.
If the object is not null, but empty, it implies that data has been returned, whereas returning null clearly indicates that nothing has been returned.
Also IMO, if you will return null, it will result in a null exception if you attempt to access members in the object, which can be useful for highlighting buggy code.
通常,如果有人试图表明没有数据,则返回空值是最好的主意。
如果对象不为null,而是为空,则表示已经返回数据,而返回null则明确表示没有返回任何内容。
此外,IMO,如果您将返回 null,如果您尝试访问对象中的成员,它将导致 null 异常,这对于突出显示错误代码很有用。
In C#, there are two different kinds of equality:
在 C# 中,有两种不同的等式:
- reference equality and
- value equality.
- 引用相等和
- 价值平等。
When a type is immutable, overloading operator == to compare value equality instead of reference equality can be useful.
当类型是不可变的时,重载运算符 == 来比较值相等而不是引用相等可能很有用。
Overriding operator == in non-immutable types is not recommended.
不建议在非不可变类型中覆盖运算符 ==。
Refer to the MSDN article Guidelines for Overloading Equals() and Operator == (C# Programming Guide)for more details.
有关更多详细信息,请参阅 MSDN 文章重载 Equals() 和运算符 ==(C# 编程指南)的指南。
回答by bigge
A totally different option (which I think is underused) is the null object pattern. It's hard to tell whether it makes sense in your particular situation, but it might be worth a try. In short, you will have a NullContact
implementation, a NullAddress
implementation and so on that you use instead of null
. That way, you can get rid of most of the null checks, of course at the expense at some thought you have to put into the design of these implementations.
一个完全不同的选项(我认为它未被充分利用)是null object pattern。很难判断它在您的特定情况下是否有意义,但可能值得一试。简而言之,您将拥有一个NullContact
实现、一个NullAddress
实现等,您可以使用它来代替null
. 这样,您可以摆脱大多数空检查,当然,代价是您必须在这些实现的设计中投入一些想法。
As Adam pointed out in his comment, this allows you to write
正如亚当在他的评论中指出的那样,这允许你写
if (person.Contact.Address.City is NullCity)
in cases where it is really necessary. Of course, this only makes sense if city really is a non-trivial object...
在确实有必要的情况下。当然,这只有在城市真的是一个非平凡的物体时才有意义......
Alternatively, the null object can be implemented as a singleton (e.g., look herefor some practical instructions concerning the usage of the null object pattern and herefor instructions concerning singletons in C#) which allows you to use classical comparison.
或者,可以将空对象实现为单例(例如,请在此处查看有关空对象模式使用的一些实用说明,在此处查看有关 C# 中单例的说明),这允许您使用经典比较。
if (person.Contact.Address.City == NullCity.Instance)
Personally, I prefer this approach because I think it is easier to read for people not familiar with the pattern.
就我个人而言,我更喜欢这种方法,因为我认为对于不熟悉该模式的人来说更容易阅读。
回答by jwg
try
{
// do some stuff here
}
catch (NullReferenceException e)
{
}
Don't actually do this.Do the null checks, and figure out what formatting you can best live with.
实际上不要这样做。进行空值检查,并找出您最适合使用的格式。
回答by Sandor Drie?nhuizen
If for some reason you don't mind going with one of the more 'over the top' solutions, you might want to check out the solution described in my blog post. It uses the expression tree to find out whether the value is null before evaluating the expression. But to keep performance acceptable, it creates and caches IL code.
如果出于某种原因您不介意采用更“顶级”的解决方案之一,您可能需要查看我的博客文章中描述的解决方案。它使用表达式树在评估表达式之前找出值是否为空。但是为了保持性能可接受,它会创建并缓存 IL 代码。
The solution allows you do write this:
该解决方案允许您这样做:
string city = person.NullSafeGet(n => n.Contact.Address.City);