Я начал этот вопрос с загрузки фона рассматриваемых типов;интерфейсы и обоснование архитектуры.
Тогда я понял - «Это ТАК - будь проще и доберись до сути».
Итак, пошло.
Iиметь такой класс:
public class AGenericType<T> : AGenericTypeBase
{
T Value { get; set; }
}
.Net, тогда, конечно, я могу сделать это:
AGenericType<AGenericType<int>> v;
Однако, в контексте использования AGenericType<T>
,бессмысленно делать это так же, как бессмысленно делать это:
Nullable<Nullable<double>> v;
Я хочу иметь возможность ограничить этот универсальный тип, чтобы создать такойэкземпляр или даже объявляют ссылку на тип, когда его T
является производным от AGenericTypeBase
- предпочтительно во время компиляции.
Теперь интересно то, что приведенный здесь пример Nullable<T>
действительно генерирует ошибку компилятора.Но я не могу понять, как Nullable<T>
ограничивает T
типами, отличными от Nullable<T>
- поскольку Nullable<T>
является структурой и единственным общим ограничением, которое я могу найти (даже в IL, который часто дает секреты компиляторакак у делегатов) where T:struct
.Так что я думаю, что нужно быть взломщиком компилятора ( РЕДАКТИРОВАТЬ: см. Ответ @Daniel Hilgarth + комментарии ниже для небольшого исследования этого ).Взлом компилятора, конечно, я не могу повторить!
Для моего собственного сценария IL и C # не допускают ограничение отрицательного утверждения вроде этого:
public class AGenericType<T> : where !T:AGenericTypeBase
(обратите внимание на '!' В ограничении)
Но какую альтернативу я могу использовать?
Я думал о двух:
1) Исключение времени выполнения, сгенерированное вконструктор AGenericType<T>
:
public AGenericType(){
if(typeof(AGenericBase).IsAssignableFrom(typeof(T)))
throw new InvalidOperationException();
}
Это на самом деле не отражает природу ошибки - потому что проблема заключается в универсальном параметре и, следовательно, в целом типе;не только этот экземпляр.
2) Итак, вместо этого то же исключение времени выполнения, но сгенерированное в статическом инициализаторе для AGenericType<T>
:
static AGenericType(){
if(typeof(AGenericBase).IsAssignableFrom(typeof(T)))
throw new InvalidOperationException();
}
Но затем я столкнулся сПроблема в том, что это исключение будет заключено в TypeInitializationException
и потенциально может вызвать путаницу (по моему опыту разработчики, которые фактически читают всю иерархию исключений, тонки на земле).
Для меня это очевидный случайдля общих ограничений «отрицательного утверждения» в IL и C # - но поскольку это вряд ли произойдет, что бы вы сделали?