我有一个这样定义的泛型方法:

public void MyMethod<T>(T myArgument)

我要做的第一件事是检查myArgument的值是否为该类型的默认值,就像这样:

if (myArgument == default(T))

但这不能编译,因为我不能保证T会实现==运算符。所以我把代码转换成这样:

if (myArgument.Equals(default(T)))

现在这个编译了,但是如果myArgument为null就会失败,这是我测试的一部分。我可以像这样添加一个显式的空检查:

if (myArgument == null || myArgument.Equals(default(T)))

现在我觉得这是多余的。ReSharper甚至建议我将myArgument == null部分更改为myArgument == default(T),这是我开始的地方。有没有更好的方法来解决这个问题?

我需要同时支持引用类型和值类型。


当前回答

不知道这是否适用于您的需求,但您可以将T约束为实现IComparable等接口的类型,然后从该接口(IIRC支持/处理空值)使用ComparesTo()方法,如下所示:

public void MyMethod<T>(T myArgument) where T : IComparable
...
if (0 == myArgument.ComparesTo(default(T)))

你可能还可以使用其他接口,比如IEquitable等等。

其他回答

(编辑)

Marc Gravell给出了最好的答案,但我想发布一个简单的代码片段来演示它。在一个简单的c#控制台应用程序中运行:

public static class TypeHelper<T>
{
    public static bool IsDefault(T val)
    {
         return EqualityComparer<T>.Default.Equals(obj,default(T));
    }
}

static void Main(string[] args)
{
    // value type
    Console.WriteLine(TypeHelper<int>.IsDefault(1)); //False
    Console.WriteLine(TypeHelper<int>.IsDefault(0)); // True

    // reference type
    Console.WriteLine(TypeHelper<string>.IsDefault("test")); //False
    Console.WriteLine(TypeHelper<string>.IsDefault(null)); //True //True

    Console.ReadKey();
}

还有一件事:使用VS2008的人可以尝试将此作为扩展方法吗?我在这里停留在2005年,我很好奇这是否会被允许。


编辑:下面是如何让它作为一个扩展方法工作:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // value type
        Console.WriteLine(1.IsDefault());
        Console.WriteLine(0.IsDefault());

        // reference type
        Console.WriteLine("test".IsDefault());
        // null must be cast to a type
        Console.WriteLine(((String)null).IsDefault());
    }
}

// The type cannot be generic
public static class TypeHelper
{
    // I made the method generic instead
    public static bool IsDefault<T>(this T val)
    {
        return EqualityComparer<T>.Default.Equals(val, default(T));
    }
}

不知道这是否适用于您的需求,但您可以将T约束为实现IComparable等接口的类型,然后从该接口(IIRC支持/处理空值)使用ComparesTo()方法,如下所示:

public void MyMethod<T>(T myArgument) where T : IComparable
...
if (0 == myArgument.ComparesTo(default(T)))

你可能还可以使用其他接口,比如IEquitable等等。

要处理所有类型的T,包括T是基本类型的情况,你需要在两种比较方法中编译:

    T Get<T>(Func<T> createObject)
    {
        T obj = createObject();
        if (obj == null || obj.Equals(default(T)))
            return obj;

        // .. do a bunch of stuff
        return obj;
    }

基于公认答案的扩展方法。

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

用法:

   private bool SomeMethod(){
       var tValue = GetMyObject<MyObjectType>();
       if (tValue == null || tValue.IsDefault()) return false;
   }

替换null来简化:

   public static bool IsNullOrDefault<T>(this T inObj)
   {
       if (inObj == null) return true;
       return EqualityComparer<T>.Default.Equals(inObj, default);
   }

用法:

   private bool SomeMethod(){
       var tValue = GetMyObject<MyObjectType>();
       if (tValue.IsNullOrDefault()) return false;
   }

试试这个:

if (EqualityComparer<T>.Default.Equals(myArgument, default(T)))

它应该编译,并执行您想要的操作。