Подтвердить что ты не робот

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?

4b9b3361

Ответ 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, который в любом случае не связан с существующими классами.