Проверка универсального типа


есть ли способ принудительно / ограничить типы, которые передаются примитивам?(bool, int, string и др.)

теперь я знаю, что вы можете ограничить параметр generic type реализацией типа или интерфейса через здесь предложения. Однако это не соответствует счету для примитивов (AFAIK), потому что они не все имеют общую основу (кроме объект прежде чем кто-то говорит! :P).

Итак, мои текущие мысли нужно просто стиснуть зубы и сделать большие переключатель заявление и бросить ArgumentException на провал..


редактировать 1:

просто для уточнения:

определение кода должно быть так:

public class MyClass<GenericType> ....

и инстанцирование:

MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)

редактировать 2

@Jon Limjap-хороший момент, и что-то я уже рассматривал.. Я уверен, что есть общий метод, который можно использовать для определения типа значения или ссылочного типа..

Это может быть полезно для мгновенного удаления многих объектов, с которыми я не хочу иметь дело (но тогда вам нужно беспокоиться о структурах, которые используются, таких как в размере).. Интересной проблемы нет? :)

вот это:

where T : struct

принято от MSDN.


мне любопытно.. Можно ли это сделать в .NET 3.X с помощью расширения методы? Создайте интерфейс и реализуйте интерфейс в методах расширения (который, вероятно, будет чище, чем бит fat switch). Кроме того, если вам нужно позже расширить до любых легких пользовательских типов, они также могут реализовать тот же интерфейс, без каких-либо изменений, необходимых для базового кода.

что вы думаете?

печальная новость заключается в том, что я работаю в рамках 2!! : D


редактировать 3

Это было так просто следуя указателю Джона Лимджапса.. Так просто я почти хочу плакать, но это здорово, потому что код работает как шарм!

так вот что я сделал (вы будете смеяться!):

код добавлен в общий класс

bool TypeValid()
{
    // Get the TypeCode from the Primitive Type
    TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));

    // All of the TypeCode Enumeration refer Primitive Types
    // with the exception of Object and Empty (Null).
    // Since I am willing to allow Null Types (at this time)
    // all we need to check for is Object!
    switch (code)
    {
        case TypeCode.Object:
            return false;
        default:
            return true;
    }
}

затем немного утилиты метод, чтобы проверить тип и бросить исключение,

private void EnforcePrimitiveType()
{
    if (!TypeValid())
        throw new InvalidOperationException(
            "Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name + 
            "' - this Class is Designed to Work with Primitive Data Types Only.");
}

все, что тогда нужно сделать, это позвонить EnforcePrimitiveType () в конструкторах классов. Дело сделано! : -)

единственный недостаток, он только создает исключение во время выполнения (очевидно), а не во время разработки.. Но это не имеет большого значения и может быть подобран с помощью утилиты, как FxCop (который мы не используем на работе).

особая благодарность Джону Лимджапу на этом!

8 62

8 ответов:

примитивы, по-видимому, указаны в TypeCode перечисление:

возможно, есть способ узнать, содержит ли объект TypeCode enum без необходимости приводить его к определенному объекту или вызывать GetType() или typeof()?

обновление это было прямо у меня под носом. Пример кода там показывает это:

static void WriteObjectInfo(object testObject)
{
    TypeCode    typeCode = Type.GetTypeCode( testObject.GetType() );

    switch( typeCode )
    {
        case TypeCode.Boolean:
            Console.WriteLine("Boolean: {0}", testObject);
            break;

        case TypeCode.Double:
            Console.WriteLine("Double: {0}", testObject);
            break;

        default:
            Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
            break;
        }
    }
}

это все еще уродливый переключатель. Но это хорошее место для начала!

public class Class1<GenericType> where GenericType : struct
{
}

этот, казалось, сделал свою работу..

в значительной степени то, что @Lars уже сказал:

//Force T to be a value (primitive) type.
public class Class1<T> where T: struct

//Force T to be a reference type.
public class Class1<T> where T: class

//Force T to be a parameterless constructor.
public class Class1<T> where T: new()

все работают в .NET 2, 3 и 3.5.

если вы можете терпеть использование заводских методов (вместо конструкторов MyClass, которые вы просили), вы всегда можете сделать что-то вроде этого:

class MyClass<T>
{
  private readonly T _value;

  private MyClass(T value) { _value = value; }

  public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
  public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
  // etc for all the primitive types, or whatever other fixed set of types you are concerned about
}

проблема здесь в том, что вам нужно будет ввести MyClass<AnyTypeItDoesntMatter>.FromInt32, что раздражает. Существует не очень хороший способ обойти это, если вы хотите сохранить приватность конструктора, но вот несколько обходных путей:

  • создать абстрактный класс MyClass. Сделай MyClass<T> наследовать от MyClass и вложить его в MyClass. Переместите статические методы в MyClass. Это будет все видимости работать, за счет того, чтобы получить доступ MyClass<T> как MyClass.MyClass<T>.
  • использовать MyClass<T> как дано. Сделайте статический класс MyClass который вызывает статические методы в MyClass<T> используя MyClass<AnyTypeItDoesntMatter> (вероятно, используя соответствующий тип каждый раз, просто для смеха).
  • (проще, но, конечно, странно) сделать абстрактный тип MyClass, который наследует от MyClass<AnyTypeItDoesntMatter>. (Для конкретности, скажем MyClass<int>.), Потому что вы можете вызывать статические методы, определенные в базовом классе через имя производного класса, теперь вы можете использовать MyClass.FromString.

это дает вам статическую проверку за счет большего количества записей.

если вы довольны динамической проверкой, я бы использовал некоторые варианты решения TypeCode выше.

@Rob,Enum ' s проскользнет через

Вы можете упростить EnforcePrimitiveType метод с помощью typeof(PrimitiveDataType).IsPrimitive собственность. Я что-то упустил?

использовать пользовательские FxCop правило, которое помечает нежелательное использование MyClass<>.

имея подобный вызов, мне было интересно, как вы, ребята, чувствовали себя IConvertible интерфейс. Это позволяет то, что требует запросчик, и вы можете расширить свои собственные реализации.

пример:

    public class MyClass<TKey>
    where TKey : IConvertible
{
    // class intentionally abbreviated
}

Я думаю об этом как о решении, хотя многие из предложенных также были частью моего выбора.

моя забота-однако-это вводит в заблуждение потенциальных разработчиков, использующих ваш класс?

Ура - и спасибо.