Использование общих ограничений с типами значений - PullRequest
6 голосов
/ 06 октября 2011

Я экспериментирую с беглыми методами расширения.

У меня есть следующий простой метод расширения для выполнения безопасного приведения.

     public static T As<T>(this Object source)
         where T : class
     {
         return source as T;
     }

Это сработало хорошо, но когда я попытался сделать этоИнтуитивно понятное использование значений типов с перегрузкой

     public static T As<T>(this ValueType source)
         where T : struct
     {
         return (T)source;
     }

Я столкнулся с проблемами.Логика разрешения метода всегда выбирает первый метод, описанный выше, и выдает синтаксическую ошибку (точно), что структура не является классом.

Есть ли способ справиться с вышеизложенным или я должен пойти по пути удаленияограничение при тестировании и обработке всех типов одним и тем же методом?

==== Редактировать: отвечать на вопросы ====

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

Я не особенно обеспокоен тем, чтобы он оставался «безопасным» исполнением.Вот как это началось, и его можно сохранить в безопасности с помощью default () - но это не совсем вопрос и код, чтобы гарантировать, что «безопасность» будет просто неясной.

Что касается выразительности, нет value.As<int>() не более выразителен, чем (int)value;но почему пользователь метода должен «просто знать», что он работает только со ссылочными типами?Я пытался проработать его в большей степени об ожидаемом поведении метода, чем о выразительной записи.

Фрагмент кода value.As<DateTime>(), выдает ошибку "Тип 'System.DateTime' должен быть ссылочным типом, чтобыиспользовать его в качестве параметра 'T' в универсальном типе или методе .... Как (объект) ".Из сообщения об ошибке, которое я вижу, разрешается использовать метод top, указанный выше, поскольку он требует ссылочный тип.

1 Ответ

3 голосов
/ 06 октября 2011

В .NET 4 вторая перегрузка выбирается на основе вашего примера кода.(Также только что протестировано на .NET 3.5, тот же результат.)

int myInt = 1;
long myLong = myInt.As<long>(); // chooses ValueType version

Однако, это только возвращает нас к месту следующего крушения.(T)source; приводит к недопустимому исключению приведения.Вы могли бы обойти это, написав метод как

public static T As<T>(this ValueType source)
    where T : struct
{
    return (T)Convert.ChangeType(source, typeof(T));
}

Однако мне интересно, чего вы на самом деле хотите достичь, так как я не вижу немедленной выгоды.(И в этом отношении, это не безопасный как версия объекта source as T.) Например, как

long myLong = myInt.As<long>();

Более выразительный или более простой в использовании, чем

long myLong = (long)myInt;
...