У меня есть общий класс в моем проекте с производными классами.
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
Есть ли способ узнать, является ли Type
объект производным GenericClass
?
t.IsSubclassOf(typeof(GenericClass<>))
не работает.
c#
generics
reflection
bernhardrusch
источник
источник
(Перемещено из-за массивного переписывания)
Кодовый ответ JaredPar фантастический, но у меня есть совет, который сделает ненужным, если ваши универсальные типы не основаны на параметрах типов значений. Я был зациклен на том, почему не работает оператор is, поэтому я также задокументировал результаты своих экспериментов для дальнейшего использования. Пожалуйста, улучшите этот ответ, чтобы еще больше повысить его ясность.
НАКОНЕЧНИК:
Если вы уверены, что ваша реализация GenericClass наследует от абстрактного неуниверсального базового класса, такого как GenericClassBase, вы можете задать тот же вопрос без каких-либо проблем, например:
IsSubclassOf ()
Мои тесты показывают, что IsSubclassOf () не работает с универсальными типами без параметров, такими как
тогда как он будет работать с
Поэтому следующий код будет работать для любого происхождения GenericClass <>, при условии, что вы готовы тестировать на основе SomeType:
Единственный раз, когда я могу представить, что вы захотите протестировать GenericClass <>, это сценарий инфраструктуры плагинов.
Мысли об операторе "есть"
Во время разработки C # не позволяет использовать непараметрические обобщения, потому что они на самом деле не являются полным типом CLR. Следовательно, вы должны объявлять универсальные переменные с параметрами, и поэтому оператор «is» является настолько мощным для работы с объектами. Между прочим, оператор «также» также не может оценивать общие параметры без параметров.
Оператор is проверяет всю цепочку наследования, включая интерфейсы.
Итак, с учетом экземпляра любого объекта, следующий метод сделает свое дело:
Это излишне, но я решил, что пойду дальше и представлю это всем.
Дано
Следующие строки кода вернули бы true:
С другой стороны, если вы хотите что-то конкретное для GenericClass, вы можете сделать это более конкретным, я полагаю, так:
Тогда вы бы протестировали так:
источник
Type
объект.typeof
оператора. Согласно документации: «Оператор typeof используется для получения объекта System.Type для типа».Я работал с некоторыми из этих образцов и обнаружил, что в некоторых случаях они отсутствуют. Эта версия работает со всеми видами дженериков: типами, интерфейсами и определениями типов.
Вот и юнит-тесты:
источник
!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent;
поэтому вы заменяете эту переменную расширением оператора if:if (parent.IsGenericType && shouldUseGenericType)
и вы получаете значение,if (parent.IsGenericType && (!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent))
которое затем уменьшается доif (parent.IsGenericType && parent.GetGenericTypeDefinition() == parent)) parent = parent.GetGenericTypeDefinition();
int j = 0;
if (j is an int && j == 0)
{ j=0; }
то, перепутал ли я мои эталонные значения и значения? Я думал, что в памяти был только один экземпляр каждого типа, поэтому две переменные, которые указывают на один и тот же тип, фактически указывают на одно и то же место в памяти.Мне кажется, что эта реализация работает в большем количестве случаев (общий класс и интерфейс с инициированными параметрами или без них, независимо от количества дочерних элементов и параметров):
Вот мои
7076 тестовых случаев:Классы и интерфейсы для тестирования:
источник
Код JaredPar работает, но только для одного уровня наследования. Для неограниченного уровня наследования используйте следующий код
источник
while
в JaredPar охватывает неограниченные уровни.Вот небольшой метод, который я создал для проверки того, что объект является производным от определенного типа. Прекрасно работает для меня!
источник
Это может быть излишним, но я использую методы расширения, такие как следующие. Они проверяют интерфейсы, а также подклассы. Он также может возвращать тип с указанным общим определением.
Например, для примера в вопросе он может проверять как универсальный интерфейс, так и универсальный класс. Возвращаемый тип может использоваться с,
GetGenericArguments
чтобы определить, что универсальным типом аргумента является «SomeType».источник
Основываясь на превосходном ответе fir3rpho3nixx и Дэвида Шмитта выше, я изменил их код и добавил тест ShouldInheritOrImplementTypedGenericInterface (последний).
источник
Все это можно легко сделать с помощью linq. Это позволит найти любые типы, которые являются подклассом универсального базового класса GenericBaseType.
источник
Простое решение: просто создайте и добавьте второй неуниверсальный интерфейс к универсальному классу:
Тогда просто проверить , что в любом случае вы хотите , используя
is
,as
,IsAssignableFrom
и т.д.Очевидно, что это возможно только в том случае, если у вас есть возможность редактировать общий класс (который, кажется, имеет OP), но он немного более элегантен и удобочитаем, чем использование метода загадочного расширения.
источник
IGenericClass
не гарантирует вам , чтоGenericClass
иGenericInterface
на самом деле расширены или реализованы. Это означает, что ваш компилятор также не позволит вам получить доступ к членам универсального класса.Добавлено в ответ @ jaredpar, вот что я использую для проверки интерфейсов:
Пример:
источник
JaredPar,
Это не сработало для меня, если я передал typeof (type <>) как toCheck. Вот что я изменил.
источник
typeof(type<>)
какtoCheck
. Также вам действительно нужна нулевая проверка, как в решении JaredPar. Кроме того, я не знаю, чего еще вы достигаете, заменивcur == generic
в своем решенииcur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()
другим, кроме ограничения своего метода, работающего только для универсальных типов. Другими словами, ничего подобного не получается за исключением:IsSubclassOfRawGeneric(typeof(MyClass), typeof(MyClass<>))
@EnocNRoll - ответ Ананды Гопала интересен, но в случае, если экземпляр не был создан заранее или вы хотите проверить с помощью определения общего типа, я бы предложил этот метод:
и используйте это как:
Существует четыре условных случая, когда оба
t
(подлежащие проверке) иd
являются универсальными типами, а два случая охватываютсяt==d
: (1)t
ниd
универсальным определением, ни (2) оба являются универсальными определениями . В остальных случаях один из них является общим определением, только когдаd
уже есть общее определение, у нас есть шанс сказать, чтоt
есть,d
но не наоборот.Он должен работать с произвольными классами или интерфейсами, которые вы хотите протестировать, и возвращает то, что вы проверяете экземпляр этого типа с помощью
is
оператора.источник
источник
Вы можете попробовать это расширение
источник
опоздал к игре об этом ... у меня тоже есть еще одна перестановка ответа JarodPar.
вот Type.IsSubClassOf (Type), предоставленный отражателем:
Исходя из этого, мы видим, что он не делает ничего особенного и похож на итеративный подход JaredPar. Все идет нормально. вот моя версия (отказ от ответственности: не полностью проверен, поэтому позвольте мне знать, если вы обнаружите проблемы)
в основном это просто метод расширения для System.Type - я сделал это, чтобы преднамеренно ограничить тип "thisType" конкретными типами, так как я сразу же использую запрос LINQ "where" для объектов Type. я уверен, что все вы, умные люди, могли бы столкнуть его с эффективным, универсальным статическим методом, если вам нужно :) код делает несколько вещей, которых код ответа не делает
остальное в основном совпадает с кодом JaredPar
источник