тест для универсального аргумента метода, являющегося классом - PullRequest
2 голосов
/ 03 июня 2011

У меня есть универсальный метод с этой подписью:

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

Если я передам, скажем, целое число этому методу, я получу ArgumentException, что переданное значение не соответствует ограничению.Это здорово, но как я могу предопределить, что то, что я передаю, будет соответствовать ограничению «класс», чтобы исключение не было выброшено?

Ответы [ 3 ]

5 голосов
/ 03 июня 2011

Компилятор уже сделает это за вас - вы должны увидеть:

Тип 'int' должен быть ссылочным типом, чтобы использовать его в качестве параметра 'T' в универсальном типе или методе 'blah.MyGenericMethod (T)'

во время компиляции.

Сложные сценарии:

  • Обобщения на дженерики на дженерики - все эти ограничения типов складываются, так что в итоге вы получите where T : class много . Иногда лучше использовать проверку времени выполнения против T
  • отражение (MakeGenericMethod и т. Д.) - опять же, просто проверьте во время выполнения

Также обратите внимание, что where T : class на самом деле не означает, что T - это класс - это означает, что это ссылочный тип, который может включать интерфейсы и делегаты. Аналогично, where T : struct на самом деле не означает, что T - это struct - это означает, что это структура, которая не Nullable<>.

1 голос
/ 03 июня 2011

Вы не можете передать int, потому что это тип значения , и вы ограничили свой метод, чтобы принимать только ссылочный тип .если вы хотите поддержать какой-либо из них, вам нужно убрать ограничение обобщений, например:

 private void MyGenericMethod<T>(T arg)
        {
            if(arg.GetType().IsValueType)
            {
                //T is value type
            }
        }
0 голосов
/ 03 июня 2011

На самом деле вы получаете ошибки компиляции, если передаваемый аргумент не является ссылочным типом. Однако, если вы укажете тип значения, вы можете обойти это, но тогда это допустимый ссылочный тип.

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 и, возможно, просто ничего не делать.

...