我需要检查null的通用对象,或者默认(T)。但我有一个问题......目前我这样做了:
if (typeof(T).IsValueType)
{
if(default(T).Equals(thing))
// Do something
else
// Do something else
}
else
{
if(thing == null)
// Do something
else
// Do something else
}
然后我最终重复自己......我不喜欢。问题如下:
thing == null;
这里ReSharper警告可能将值类型与'null'进行比较。
thing == default(T);
这里我遇到编译错误:无法将运算符'=='应用于'T'和'T'类型的操作数。
thing.Equals(null|default(T));
thing
显然可以为null(这就是我必须检查的原因!),因此会导致NullReferenceException。
null|default(T).Equals(thing);
null和default(T)通常也为空...
有干净的方法吗?
答案 0 :(得分:53)
这样做的正确方法是:
return EqualityComparer<T>.Default.Equals(value, default(T))
没有拳击。您甚至可以定义这样的扩展方法:
public static void bool IsDefault<T>(this T value)
{
return EqualityComparer<T>.Default.Equals(value, default(T));
}
..并像这样调用它:
return entry.IsDefault();
尽管如此,我个人并不关心T上的扩展方法(例如此对象IsNull()),因为它有时会妨碍可读性。
答案 1 :(得分:26)
如果拳击不是问题,你可以使用:
object.Equals(value, default(T))
答案 2 :(得分:8)
当我需要测试值是否为NULL时,我使用下面的方法。我通常在调用采用任何类型但不是空值的方法时使用它,例如Cache。
public static bool IsNull<T>(this T value)
{
var type = typeof(T);
return (type.IsClass || Nullable.GetUnderlyingType(type) != null)
&& EqualityComparer<T>.Default.Equals(value, default(T));
}
答案 3 :(得分:2)
目前我能想到的最好的事情是:
return value == null || value.Equals(default(T));
编辑:
显然,有一种我不知道的静态object.Equals
方法:
return object.Equals(value, default(T));
这样更好。
答案 4 :(得分:2)
有点拳击可以完成这项工作。
static bool IsNullOrDefault<T>(T value)
{
return ((object)default(T)) == null ?
((object)value) == null :
default(T).Equals(value);
}
答案 5 :(得分:1)
你可以通过注意静态确定类型的可空性来完全避免装箱。
以下是您可以做的事情:
isDefault
的名为Predicate<T>
的私有静态只读变量v==null
或default(T).Equals(v)
isDefault(x)
代替x==null
以下是一个例子:
public class Example<T> {
private static readonly Predicate<T> isDefault;
static Example() {
// Nullability check is a bit ugly, but we do it once per T,
// so what the heck...
if (typeof(T).IsValueType &&
(!typeof(T).IsGenericType
|| typeof(T).GetGenericTypeDefinition() != typeof(Nullable<>)
)) {
// This is safe because T is not null
isDefault = val => default(T).Equals(val);
} else {
// T is not a value type, so its default is null
isDefault = val => val == null;
}
}
public bool Check(T value) {
// Now our null-checking is both good-looking and efficient
return isDefault(value);
}
}
答案 6 :(得分:0)
通过测试:
public class DefaultOrNullChecker<T> {
public bool Check(object x) {
return object.ReferenceEquals(x, null) || x.Equals(default(T));
}
}
[TestFixture]
public class Tests {
[Test] public void when_T_is_reference_type() {
Assert.IsFalse(new DefaultOrNullChecker<Exception>().Check(new Exception()));}
[Test] public void when_T_is_value_type() {
Assert.IsFalse(new DefaultOrNullChecker<int>().Check(123)); }
[Test] public void when_T_is_null() {
Assert.IsTrue(new DefaultOrNullChecker<Exception>().Check(null));}
[Test] public void when_T_is_default_value() {
Assert.IsTrue(new DefaultOrNullChecker<int>().Check(0)); }
}
答案 7 :(得分:-1)
这有什么问题?
if (thing == default(T)) { }
如果它是值类型,那么JIT将完全删除该语句。