2014-01-08 3 views
0

У меня есть несколько классов (один из которых называется Pet), которые расширяют класс Animal. Если у меня есть общий метод, могу ли я использовать typeof для сравнения с базовым классом?Рассмотрите все унаследованные классы при использовании typeof

if (typeof(T) == typeof(Animal)) 
{ 
    return ((Animal)pet).Color; 
} 

Что происходит в моем коде, так это то, что этот раздел полностью пропускается. Это нежелательно в этом конкретном примере, так как Pet наследует от Animal.

+2

Почему бы вам не попробовать работает это выяснить. Обратите внимание, что даже если бы вы могли, вы не должны *. Обычно это признак плохо разработанного кода, который должен явно проверять тип объекта. – Servy

+0

Используйте 'if (pet is Animal)' или 'Animal a = pet as Animal; if (a! = null) return a.Color; ' –

+0

@Servy Я задаю вопрос, потому что код, который у меня в настоящее время не работает. –

ответ

2

Вместо использования typeof(T) == typeof(Animal), сделайте следующее:

var animal = pet as Animal; 
if(animal != null) 
    return animal.Color; 

Это экономит вам дополнительную проверку типа.

Примечание о as и is

as могут быть использованы только для ссылочных типов. Если вы попытаетесь использовать с помощью as, и он не сработает ... он вернет null. Если вы просто хотите проверить, имеет ли значение определенный тип, используйте is. Он возвращает boolean.

Where ключевое слово

Но, позволяет также смотреть на то, что вы можете сделать с дженериков!

public void Foo<T>(T pet) 
    where T : Animal 
{ 
} 

Обратите внимание, что ключевое слово where. Это заставит во время компиляции T типа Animal. Таким образом ... вам даже не нужно проверять!

Это значит, ваша функция может выглядеть следующим образом:

public void Foo<T>(T pet) 
    where T : Animal 
{ 
    return pet.Color; 
} 

уборщик и быстрее!

+0

Это «примечание о как и есть» неверно из-за слишком большой общности. Он не будет возвращать значение по умолчанию, которое вы пытались выполнить. На самом деле это будет, но это значение по умолчанию всегда «null». Вы не можете использовать оператор 'as' для типов, которые не являются ссылочными типами. И все ссылочные типы имеют значение по умолчанию «null». Представьте себе неуклюжий дизайн, в котором 'ANYTHING_OTHER_THAN_A_BOOL как bool' вернет' false'. Попробуйте представить такой мир и помните, что для 'bool' существует ровно два значения. Одна половина этих значений была бы ловушкой для всего, кроме «истины» :) –

+0

@EduardDumitru Это неверно. Вы можете использовать 'as' с нулевыми типами значений, которые не являются ссылочными типами, но на самом деле являются типами значений, и * * * присваивает значение по умолчанию указанным типам в случае, если тип приведения не удался. Ваше предлагаемое изменение изменит правильное утверждение на неверный оператор. – Servy

+0

Достаточно честный ... Я не думал о том, что, возможно, не общеизвестно, что требуются ссылочные типы. – Andrew

2

Хотя я бы лично идти по пути оператора в C# as для большинства из этих ситуаций (см ответа Андрея), вы можете также использовать Type.IsAssignableFrom, в зависимости от ваших потребностей:

if (typeof(Animal).IsAssignableFrom(typeof(T))) 
{ 
    return ((Animal)pet).Color; 
} 

На стороне записки, Я обычно предпочитаю Type.IsAssignableFrom более Type.IsSubclassOf, потому что IsAssignableFrom также работает с интерфейсами.

О, вы можете также использовать is:

if (pet is Animal) 
{ 
    return ((Animal)pet).Color; 
} 
+0

Да, да. Результат вызова 'IsAssignableFrom' (как можно увидеть здесь: http://msdn.microsoft.com/en-us/library/system.type.isassignablefrom(v=vs.110).aspx) - значение истины вопроса: могу ли я сделать это: 'Source s = ...; Назначение d = s; 'неявным образом? Будет ли это скомпилировано, если я не коснусь каких-либо операторов преобразования? –

Смежные вопросы