52

While trying to learn Unity, I keep seeing the following code for overriding GetControllerInstance in MVC:

if(!typeof(IController).IsAssignableFrom(controllerType)) { ... }

this seems to me a pretty convoluted way of basically writing

if(controllerType is IController) { ... }

I appreciate there are subtle differences between is and IsAssignableFrom, ie IsAssignableFrom doesn't include cast conversions, but I'm struggling to understand the implication of this difference in practical scenarios.

When is it imporantant to choose IsAssignableFrom over is? What difference would it make in the GetControllerExample?

if (!typeof(IController).IsAssignableFrom(controllerType))
      throw new ArgumentException(...);
return _container.Resolve(controllerType) as IController;
fearofawhackplanet
  • 52,166
  • 53
  • 160
  • 253

4 Answers4

81

It's not the same.

if(controllerType is IController)

would always evaluate to false since controllerType is always a Type, and a Type is never an IController.

The is operator is used to check whether an instance is compatible to a given type.

The IsAssignableFrom method is used to check whether a Type is compatible with a given type.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Ah ok the difference is obvious now. I should have spotted that! – fearofawhackplanet Jun 10 '10 at 11:02
  • So my guess is if `T` and `U` are generic types then `typeof(T).IsAssignableFrom(typeof(U))` is the same as `new T() is U`? – orad Feb 19 '14 at 22:52
  • 2
    No but it would be the same as `new U() is T`. T would be the base type. I always get tripped up by that. I just remember that `IsAssignableFrom` goes opposite of the `is` operator. – Jordan Nov 02 '15 at 19:30
21

typeof(IController).IsAssignableFrom(controllerType) tests a Type against the interface. The is operator tests an instance against the interface.

Femaref
  • 60,705
  • 7
  • 138
  • 176
16

is keyword is only applicable for instances while Type.IsAssignableFrom() is only applicable for types.

example of is

string str = "hello world";
if(str is String)
{
    //str instance is of type String
}

Note that str is an instance and not the type.

example of IsAssignableFrom()

string str = "hello world";
if(typeof(Object).IsAssignableFrom(str.GetType()))
{
    //instances of type String can be assigned to instances of type Object.
}

if(typeof(Object).IsAssignableFrom(typeof(string)))
{
    //instances of type String can be assigned to instances of type Object.
}

Note that, argument to IsAssignableFrom() is not the instance of String, it's the Type object representing String type.

this. __curious_geek
  • 42,787
  • 22
  • 113
  • 137
5

A notable difference is also that 'is' makes intuitive sense for testing inheritance or interface implementation, whereas IsAssignableFrom makes anything but sense on the face of it. The name of the Type.IsAssignableFrom method is vague and confusing when applied to testing inheritance or detecting interface implementations. The following wrapper for these purposes would make for much more intuitive, readable application code:

    public static bool CanBeTreatedAsType(this Type CurrentType, Type TypeToCompareWith)
    {
        // Always return false if either Type is null
        if (CurrentType == null || TypeToCompareWith == null)
            return false;

        // Return the result of the assignability test
        return TypeToCompareWith.IsAssignableFrom(CurrentType);
    }

Then, one can have more understandable client syntax like:

    bool CanBeTreatedAs = typeof(SimpleChildClass).CanBeTreatedAsType(typeof(SimpleClass));
    CanBeTreatedAs = typeof(SimpleClass).CanBeTreatedAsType(typeof(IDisposable));

The advantage of this method instead of the 'is' keyword is that it can be used at run-time to test unknown, arbitrary Types, whereas the 'is' keyword (and a generic Type parameter) requires compile-time knowledge of specific Types.

Mark Jones
  • 2,024
  • 1
  • 19
  • 12
  • I don't see how `IsAssignableFrom` is completely unintuitive. In a polymorphic type system, any type can be assigned a value from any of its subtypes, i.e. you can do something like: `SimpleBaseClass myVar = new SimpleChildClass()`. `IsAssignableFrom` tells you whether such a polymorphic assignment would be legal, and thus whether one type is a subtype-or-equal-to another. – zstewart May 01 '16 at 21:29