IsAssignableFrom, IsInstanceOfType и ключевое слово, в чем разница?
У меня есть метод расширения для безопасного создания объектов, который выглядит следующим образом:
public static T SafeCastAs<T>(this object obj) {
if (obj == null)
return default(T);
// which one I should use?
// 1. IsAssignableFrom
if (typeof(T).IsAssignableFrom(obj.GetType()))
return (T)obj;
// 2. IsInstanceOfType
if (typeof(T).IsInstanceOfType(obj))
return (T) obj;
// 3. is operator
if (obj is T)
return (T) obj;
return default(T);
}
Как вы можете видеть, у меня есть 3 варианта, и какой из них я должен использовать? На самом деле в чем разница между операторами IsAssignableFrom
, IsInstanceOfType
и is
?
Ответы
Ответ 1
Вы используете все, что у вас есть.
Если у вас есть экземпляр и статический тип, который вы хотите проверить, используйте is
.
Если у вас нет статического типа, у вас есть только объект Type
, но у вас есть экземпляр, который вы хотите проверить, используйте IsInstanceOfType
.
Если у вас нет экземпляра, и вы просто хотите проверить совместимость между теоретическим экземпляром Type
и другим Type
, используйте IsAssignableFrom
.
Но действительно кажется, что вы просто перепрограммируете как оператор (за исключением того, что ваш будет работать и для типов с нулевыми значениями, который обычно не является большим ограничением).
Ответ 2
Я предполагаю, что вы эффективно реализуете версию оператора as
, который работает со значениями типов, а также с ссылочными типами.
Я бы пошел за:
public static T SafeCastAs<T>(this object obj)
{
return (obj is T) ? (T) obj : default(T);
}
IsAssignableFrom
работает с типами, а is
работает с экземплярами. Они дадут вам те же результаты в вашем случае, поэтому вы должны использовать простейшую версию IMHO.
Что касается IsInstanceOfType
: это реализовано в терминах IsAssignableFrom
, поэтому разницы не будет.
Вы можете доказать, что с помощью Reflector посмотреть определение IsInstanceOfType()
:
public virtual bool IsInstanceOfType(object o)
{
if (o == null)
{
return false;
}
return this.IsAssignableFrom(o.GetType());
}
Ответ 3
Думаю, вам следует просто " as вместо обычного" SafeCastAs". Но это будет работать только для классов (не структур), поэтому, если вы хотите использовать этот метод для структур, я также могу его получить.
Оператор "в принципе" дает вам то же самое, что Type.IsAssignableFrom, поэтому вы можете сохранить только "есть", он проверяет, можете ли вы безопасно использовать obj для T без исключений. Таким образом, он будет охватывать как предыдущие проверки в вашем методе. Но вы должны знать, что он не проверяет, можете ли вы назначить obj для T из-за пользовательских преобразований: explicit и неявные ключевые слова.
Ответ 4
Эти функции и операторы имеют разное значение. Если у вас есть объекты, вы всегда можете получить типы. поэтому вы не работаете над тем, что имеете, но делаете то, что нужно сделать.
Когда вы работаете с иерархией классов, различия очень ясны.
Посмотрите на следующий пример
class ABase
{
}
class BSubclass : ABase
{
}
ABase aBaseObj = new ABase();
BSubclass bSubclassObj = new BSubclass();
ABase subObjInBaseRef = new BSubclass();
Различные операции дают разные результаты.
typeof(ABase).IsInstanceOfType(aBaseObj) = True
typeof(ABase).IsInstanceOfType(bSubclassObj) = True
typeof(ABase).IsInstanceOfType(bSubclassObj) = True
typeof(BSubclass).IsInstanceOfType(aBaseObj) = False
bSubclassObj is ABase = True
aBaseObj is BSubclass = False
subObjInBaseRef is BSubclass = True
subObjInBaseRef is BSubclass = True
typeof(ABase).IsAssignableFrom(typeof(BSubclass)) = True
typeof(BSubclass).IsAssignableFrom(typeof(ABase))= False
Если ни одна иерархия не может быть одинаковой.
Но если вы работаете с иерархией, IsAssignableFrom
, is и IsInstanceOfType
дают разные результаты.
Есть более возможные комбинации, которые можно было бы попробовать. Например, вы можете ввести класс C, который в любом случае не связан с существующими классами.