C#:GenericType == null 的替代方案

发布于 2024-07-14 14:46:15 字数 749 浏览 6 评论 0原文

我需要检查通用对象是否为空或默认(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) 通常也为 null...

有没有一种干净的方法来做到这一点?

I need to check a generic object for null, or default(T). But I have a problem... Currently I have done it like this:

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
}

But then I end up repeating myself... which I don't like. The problem is the following:

thing == null;

Here ReSharper warns about Possible compare of value type with 'null'.

thing == default(T);

Here I get compiler error: Cannot apply operator '==' to operands of type 'T' and 'T'.

thing.Equals(null|default(T));

thing can obviously be null (that's why I have to check!), so will cause NullReferenceException.

null|default(T).Equals(thing);

null and default(T) is very often null as well...

Is there a clean way to do this??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

情泪▽动烟 2024-07-21 14:46:15

正确的做法是:

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()),因为它有时会妨碍可读性。

The proper way to do this is:

return EqualityComparer<T>.Default.Equals(value, default(T))

No boxing. You could even define an extension method like this:

public static void bool IsDefault<T>(this T value)
{
    return EqualityComparer<T>.Default.Equals(value, default(T));
}

.. and invoke it like this:

return entry.IsDefault();

Though, I personally don't care for extension methods on T (e.g. this object IsNull()) since it hampers readability sometimes.

韶华倾负 2024-07-21 14:46:15

如果拳击不是问题,您可以使用:

object.Equals(value, default(T))

If boxing isn't an issue, you could just use:

object.Equals(value, default(T))
何处潇湘 2024-07-21 14:46:15

当我需要测试该值是否为 NULL 时,我使用下面的方法。 我通常在调用采用任何类型但不包括空值的方法(例如缓存)时使用此方法。

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

}

When I need to test if the value is NULL I use the method below. I typically use this when calling methods that take any type but not nulls such as the 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));

}
臻嫒无言 2024-07-21 14:46:15

打一点拳击就可以了。

    static bool IsNullOrDefault<T>(T value)
    {
        return ((object)default(T)) == null ?
            ((object)value) == null :
            default(T).Equals(value);
    }

A bit of boxing will do the job just fine.

    static bool IsNullOrDefault<T>(T value)
    {
        return ((object)default(T)) == null ?
            ((object)value) == null :
            default(T).Equals(value);
    }
友谊不毕业 2024-07-21 14:46:15

我目前能想到的最好的事情是:

return value == null || value.Equals(default(T));

编辑:

显然,有一个我不知道的静态 object.Equals 方法:

return object.Equals(value, default(T));

这更好。

Best thing I can think of at the moment is:

return value == null || value.Equals(default(T));

Edit:

Apparently, there's a static object.Equals method I was not aware of:

return object.Equals(value, default(T));

This is better.

墨小沫ゞ 2024-07-21 14:46:15

您可以通过注意可以静态确定类型的可为空性来完全避免装箱。

您可以执行以下操作:

  1. 在泛型类中声明一个名为 isDefault 的私有静态只读变量,其类型为 Predicate
  2. 向您的泛型类添加一个静态初始值设定项,检查 T 的可为空性,并根据结果将 isDefault 设置为 v==nulldefault(T).Equals(v)
  3. 使用 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);
    }

}

You can avoid boxing altogether by noting that nullability of a type can be determined statically.

Here is what you can do:

  1. Declare a private static read-only variable called isDefault of type Predicate<T> in your generic class
  2. Add a static initializer to your generic class, where you check T's nullability, and set isDefault to either v==null or default(T).Equals(v) depending on the outcome
  3. Use isDefault(x) instead of x==null in the rest of your code

Here is an example:

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

}
猫瑾少女 2024-07-21 14:46:15

通过测试:

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

With Tests:

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)); }
}
七堇年 2024-07-21 14:46:15

这有什么问题吗?

if (thing == default(T)) { }

如果它是值类型,那么 JIT 将简单地完全删除该语句。

What is wrong with this?

if (thing == default(T)) { }

If it is a value type then the JIT will simply remove the statement altogether.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文