Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 作为类的泛型方法参数的测试_C#_Generics_Constraints - Fatal编程技术网

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