Проверка общего типа

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

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

Что вы думаете, ребята?

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

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

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

Julien 20.02.2012 12:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
71
1
28 647
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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

Похоже, это сработало ...

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

Ответ принят как подходящий

Примитивы, по-видимому, указаны в перечислении 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;
        }
    }
}

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

Хороший момент, и то, что я уже обдумывал ... Я уверен, что существует универсальный метод, который можно использовать для определения того, имеет ли тип тип значения или ссылочный тип. Это может быть полезно для мгновенного удаления большого количества объектов Я не хочу заниматься (но тогда вам нужно беспокоиться об используемых структурах, таких как Размер) .. Интересная проблема, нет? :) Обновлено: Ах да, вот она: где T: struct Взято из MSDN.

Rob Cooper 12.08.2008 19:17

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

Jon Limjap 12.08.2008 19:14

Мне любопытно ... Интересно, можно ли это сделать в .NET 3.x, используя методы расширения ... Создайте интерфейс ... Реализуйте интерфейс в методах расширения ... (который, вероятно, был бы чище, чем немного толстый переключатель) .. Кроме того, если впоследствии вам потребуется расширить его до любых облегченных пользовательских типов, они также могут реализовать тот же интерфейс без каких-либо изменений в базовом коде. Что вы думаете, ребята? Печальная новость - я работаю в рамках 2 !! : D Обновлено: Выйдя из офиса примерно через 5 минут, заберу это, когда вернусь домой! : D

Rob Cooper 12.08.2008 19:23

> публичный класс Class1where> GenericType: struct {}>> Похоже, это сработало. Проблема, которую я вижу с этой реализацией, заключается в том, что если у вас есть настраиваемая структура, она все равно будет восприниматься как примитив, что не так.

Jon Limjap 12.08.2008 20:03

Примерно то, что уже сказал @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 выше.

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

Передача строки в этот оператор возвращает False, и плакат указал, что ему нужна строка для возврата True. .NET считает char примитивом, но не строкой.

Nicholas 05.11.2008 13:55

@Rob, 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

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

Пример:

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

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

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

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

Другие вопросы по теме