测试泛型方法参数是否为类

发布于 2024-11-11 13:36:27 字数 211 浏览 2 评论 0原文

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

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

如果我向此方法传递一个整数,我会收到一个 ArgumentException ,表明传递的值与限制不匹配。这很棒,但是我如何预先确定我传递的内容将与“类”约束匹配,以便不引发异常?

I have a generic method with this signature:

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

If I pass, say, an integer to this method, I get an ArgumentException that the passed value does not match the restriction. This is great, but how can I predetermine that what I am passing will match the "class" constraint so that the exception is not thrown?

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

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

发布评论

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

评论(3

笛声青案梦长安 2024-11-18 13:36:27

编译器已经为你做到了这一点 - 你实际上应该看到:

类型“int”必须是引用类型,才能将其用作泛型类型或方法“blah.MyGenericMethod(T)”中的参数“T”

在编译时将其用作泛型类型或方法“blah.MyGenericMethod(T)”中的参数“T”。

棘手的场景是:

  • 泛型之上的泛型之上的泛型 - 所有这些类型约束都堆叠起来,所以你最终会得到 where T : class 很多 。有时最好对 T
  • 反射使用运行时验证(MakeGenericMethod 等) - 同样,只需在运行时检查

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

The compiler will already do that for you - you should actually see:

The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'blah.MyGenericMethod(T)'

at compile-time.

The tricky scenarios are:

  • generics upon generics upon generics - all those type-constraints stack, so you end up with where T : class a lot. Sometimes it is better to use runtime validation against T
  • reflection (MakeGenericMethod, etc) - again, just check at runtime

Also, note that where T : class doesn't actually mean T is a class - it means it is a reference-type, which can include interfaces and delegates. Likewise, where T : struct doesn't actually mean T is a struct - it means it is a struct that is not Nullable<>.

傻比既视感 2024-11-18 13:36:27

您不能传递int,因为它是值类型,并且您已将您的方法限制为仅接受引用类型
如果您想支持其中任何一个,您需要删除泛型约束,如下所示

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

You can not pass int because it is a value type and you have constrained your Method to accept only reference type.
if you want to support any of those you need to remove the generics constrain like following

 private void MyGenericMethod<T>(T arg)
        {
            if(arg.GetType().IsValueType)
            {
                //T is value type
            }
        }
寄与心 2024-11-18 13:36:27

如果传递的参数不是引用类型,您实际上会收到编译错误。但是,如果您对值类型进行装箱,则可以绕过该问题,但它是有效的引用类型。

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,而根据 typeof 检查 GetType 仅需要在该级别键入:

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

显然在您的情况中,您不会想抛出ArgumentException,并且可能什么都不做。

You actually get compilation errors if the argument being passed is not a reference type. If you box a value type, however, you can get around that, but then it's a valid reference type.

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
        {

        }
    }
}

If you are getting this error because you do something at runtime, such as use reflection to call the method, or you box value types, then you will simply need to check the parameter before you use it:

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

Note that this will catch all value types, whether they are boxed or not. Also note that using is also matches true for the type in it's hierarchy (base / derived classes), whereas checking GetType against typeof takes only the type at that level:

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

Obviously in your case you won't want to throw an ArgumentException and perhaps just do nothing.

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