amiry jd
amiry jd

Reputation: 27605

IsAssignableFrom, IsInstanceOfType and the is keyword, what is the difference?

I have an extension method to safe casting objects, that looks like this:

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);
}

As you can see, I have 3 choice, so which one I should to use? Actually what is the difference between IsAssignableFrom, IsInstanceOfType, and is operator?

Upvotes: 50

Views: 19259

Answers (4)

Sandeep Dixit
Sandeep Dixit

Reputation: 1046

These functions and operators have different meaning. If you have objects you can always get types. so you do not work on what you have, but you do what needs to be done.

When you are working with a class hierarchy differences are very clear.

Look at following example

      class ABase
        {

        }

        class BSubclass : ABase
        {

        }
    ABase aBaseObj = new ABase();
                BSubclass bSubclassObj = new BSubclass();

                ABase subObjInBaseRef = new BSubclass();

Different operations yield different results.

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

In case on no hierarchy, may be everything was same. But if you work with hierarchy, IsAssignableFrom , is , and IsInstanceOfType yield different results.

There are more possible combinations that could be tried. For example, you can introduce a class C which is not related in anyway with existing classes in this example.

Upvotes: 1

outcoldman
outcoldman

Reputation: 11832

I guess you should just go with "as" instead of your custom "SafeCastAs". But this will work only for classes (not structs), so if you want to use this method for structs as well I can get it.

Operator "is" basically gives you the same as Type.IsAssignableFrom, so you can keep only "is", it checks if you can safely cast obj to T, without exceptions. So it will cover both previous checks in your method. But you should be aware about that it does not check if you can assign obj to T, because of user defined conversions: explicit and implicit keywords.

Upvotes: 3

Matthew Watson
Matthew Watson

Reputation: 109832

I guess you're effectively implementing a version of the as operator that works with value types as well as reference types.

I'd go for:

public static T SafeCastAs<T>(this object obj)
{
    return (obj is T) ? (T) obj : default(T);
}

IsAssignableFrom works with types, and is works with instances. They will give you the same results in your case, so you should use the simplest version IMHO.

As for IsInstanceOfType:That is implemented in terms of IsAssignableFrom, so there will be no difference.

You can prove that by using Reflector to look at the definition of IsInstanceOfType():

public virtual bool IsInstanceOfType(object o)
{
    if (o == null)
    {
        return false;
    }
    return this.IsAssignableFrom(o.GetType());
}

Upvotes: 10

Jacob
Jacob

Reputation: 1749

You use whatever you have the information for.

If you have an instance and a static type you want to check against, use is.

If you don't have the static type, you just have a Type object, but you have an instance you want to check, use IsInstanceOfType.

If you don't have an instance and you just want to check the compatibility between a theoretical instance of a Type and another Type, use IsAssignableFrom.

But really is seems like you are just re-implementing the as operator (except that yours would also work for non-nullable value types, which is usually not a big limitation).

Upvotes: 76

Related Questions