测试泛型方法参数是一个类

时间:2011-06-03 08:40:08

标签: c# generics constraints

我有一个带有此签名的通用方法:

private void MyGenericMethod<T>(T arg) where T : class
{}

如果我传递一个整数给这个方法,我得到一个ArgumentException,传递的值与限制不匹配。这很好,但我如何预先确定我传递的内容是否与“类”约束匹配,以便不抛出异常?

3 个答案:

答案 0 :(得分:5)

编译器已经为你做了 - 你应该看到:

  

类型'int'必须是引用类型才能在泛型类型或方法'blah.MyGenericMethod(T)'

中将其用作参数'T'

在编译时。

棘手的情况是:

  • 关于泛型的泛型的泛型 - 所有这些类型约束堆栈,因此您最终得到where T : class 很多 。有时最好对T
  • 使用运行时验证
  • 反射(MakeGenericMethod等) - 再次,只需在运行时检查

另请注意,where T : class 实际上并不意味着T是一个类 - 这意味着它是一个引用类型,可以包括接口和委托。同样,where T : struct实际上并不意味着Tstruct - 这意味着它是一个不是Nullable<>的结构。

答案 1 :(得分:1)

您无法通过int,因为它是值类型,并且您已将Method限制为仅接受引用类型。 如果你想支持任何你需要删除泛型约束的那些

 private void MyGenericMethod<T>(T arg)
        {
            if(arg.GetType().IsValueType)
            {
                //T is value type
            }
        }

答案 2 :(得分:0)

如果传递的参数不是引用类型,则实际上会出现编译错误。但是,如果您输入值类型,则可以绕过它,但它是一个有效的引用类型。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication29
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 0;
            object o = (object)i;
            MyMethod(o);
            MyMethod(i); // Doesn't compile.
        }

        static void MyMethod<T>(T arg) where T : class
        {

        }
    }
}

如果由于在运行时执行某些操作而遇到此错误,例如使用反射来调用方法,或者您使用框值类型,则只需在使用之前检查参数:

static void MyMethod<T>(T arg) where T : class
{
    if (arg is ValueType)
        throw new ArgumentException();
}

请注意,这将捕获所有值类型,无论它们是否已装箱。另请注意,使用is对于其层次结构中的类型(基类/派生类)也匹配true,而针对GetType检查typeof仅采用该级别的类型:

int i = 0;
bool b = i is object;
b = i.GetType() == typeof(object);

显然在你的情况下你不想抛出ArgumentException,也许什么都不做。