Вопрос

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

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

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


РЕДАКТИРОВАТЬ 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 с использованием методов расширения?Создайте интерфейс и реализуйте его в методах расширения (что, вероятно, будет чище, чем немного толстый переключатель).Кроме того, если впоследствии вам понадобится расширить возможности каких-либо облегченных пользовательских типов, они также могут реализовать тот же интерфейс без каких-либо изменений в базовом коде.

Ребята, что вы думаете?

Печальная новость: я работаю в Framework 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 (которым мы не пользуемся на работе).

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

Это было полезно?

Решение

Примитивы, по-видимому, указаны в 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, описанного выше.

@Роб, Enumпроскользнет через TypeValid функционировать так, как есть TypeCode является Integer.Я обновил функцию, чтобы также проверять Enum.

Private Function TypeValid() As Boolean
    Dim g As Type = GetType(T)
    Dim code As TypeCode = Type.GetTypeCode(g)

    ' All of the TypeCode Enumeration refer Primitive Types
    ' with the exception of Object and Empty (Nothing).
    ' Note: must also catch Enum as its type is Integer.
    Select Case code
        Case TypeCode.Object
            Return False
        Case Else
            ' Enum's TypeCode is Integer, so check BaseType
            If g.BaseType Is GetType(System.Enum) Then
                Return False
            Else
                Return True
            End If
    End Select
End Function

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

Используйте индивидуальный FXCop правило, которое сигнализирует о нежелательном использовании MyClass<>.

Имея похожую проблему, мне было интересно, что вы, ребята, думаете о IКонвертируемый интерфейс.Он позволяет выполнять требования запрашивающей стороны, и вы можете расширить его своими собственными реализациями.

Пример:

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

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

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

Приветствую - и спасибо.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top