C# 作为类的泛型方法参数的测试
我有一个具有此签名的通用方法:C# 作为类的泛型方法参数的测试,c#,generics,constraints,C#,Generics,Constraints,我有一个具有此签名的通用方法: private void MyGenericMethod<T>(T arg) where T : class {} private void MyGenericMethod(T arg),其中T:class {} 如果我向这个方法传递一个整数,我会得到一个ArgumentException,即传递的值与限制不匹配。这很好,但是我如何才能预先确定我传递的内容将与“类”约束匹配,以便不会引发异常?您不能传递int,因为它是值类型,并且您已将您的方法约束
private void MyGenericMethod<T>(T arg) where T : class
{}
private void MyGenericMethod(T arg),其中T:class
{}
如果我向这个方法传递一个整数,我会得到一个ArgumentException,即传递的值与限制不匹配。这很好,但是我如何才能预先确定我传递的内容将与“类”约束匹配,以便不会引发异常?您不能传递
int
,因为它是值类型,并且您已将您的方法约束为只接受引用类型。
如果您想支持其中任何一个,您需要删除泛型约束,如下所示
private void MyGenericMethod<T>(T arg)
{
if(arg.GetType().IsValueType)
{
//T is value type
}
}
private void MyGenericMethod(T arg)
{
if(arg.GetType().IsValueType)
{
//T是值类型
}
}
如果传递的参数不是引用类型,则实际上会出现编译错误。但是,如果您选择了值类型,您可以绕过它,但它是一个有效的引用类型
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
{
}
}
}
显然,在您的情况下您不想抛出一个
ArgumentException
,可能什么都不做。编译器已经为您完成了这项工作-您应该看到:
类型“int”必须是引用类型,才能将其用作泛型类型或方法“blah.MyGenericMethod(T)”中的参数“T”
在编译时
棘手的情况是:
- 泛型上泛型上泛型上泛型-所有这些类型约束堆叠在一起,因此您最终得到了
很多。有时对其中T:class
T
- 反射(
,等等)-同样,只需在运行时检查MakeGenericMethod
另外,请注意,
其中T:class
实际上并不意味着T
是一个类,它意味着它是一个引用类型,可以包括接口和委托。同样地,其中T:struct
实际上并不意味着T
是一个struct
——它意味着它是一个不可为null的结构
删除where子句并用is
操作符检查方法内部?()编译器是为您做这件事的,您更广泛的情况是什么?编译器无法捕获您的案例?如果您不知道您传递的内容是否有效,您是否可以尝试/捕获异常?我同意Adam的观点,但是了解为什么你不知道你在传递什么可能是回答你问题的关键。你能展示一下生成ArgumentException
?不知道你所处的情况,并假设在运行时发生了绕过编译器检查的事情(使用反射或其他方法),我建议只检查一下类型。我在下面修改了我的答案。小心使用is
,因为它也与基类匹配。是的,这正是发生的情况,但我想避免由此产生的数千个抛出和捕获的异常。我实际上是在用MakeGenericMethod调用该方法,但传递的类型是动态的(在循环中),我希望在调用该方法之前加入一个简单的if,以避免出现异常。@Craig您从未提到MakeGenericMethod;p只需检查类型-!type.IsValueType
可能足够好,或者type.IsClass | | type.IsInterface
完美,IsClass和IsValueType正是我不知道和想要的。这与我想要的正好相反。我只想传递和处理引用类型。同样的逻辑也可以,检查arg.GetType().IsValueType,并相应地调用该方法。
static void MyMethod<T>(T arg) where T : class
{
if (arg is ValueType)
throw new ArgumentException();
}
int i = 0;
bool b = i is object;
b = i.GetType() == typeof(object);