开发者

test for generic method argument being a class

开发者 https://www.devze.com 2023-03-09 23:47 出处:网络
I have a generic method with this signature: private void MyGenericMethod<开发者_如何学C;T>(T arg) where T : class

I have a generic method with this signature:

private void MyGenericMethod<开发者_如何学C;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?


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<>.


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
            }
        }


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消