BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Reflection
.NET 3.5+

Checking if Types are Compatible

Sometimes is it necessary to determine if an object of one type can be assigned to a variable of another, this being possible either due to inheritance or because of the implementation of an interface. You can make such determinations using reflection.

IsAssignableFrom

In previous articles we've seen how you can use reflection to find classes that are a subclass of another, either directly or indirectly, and classes that implement a specified interface. In this article we'll look at a method that combines features from both approaches and allows you to determine if one type is assignable to another due to the implementation of an interface or because of inheritance.

To perform such a check, you can use the Type class's IsAssignableFrom method, passing the second type to its parameter. The name of the method is somewhat ambiguous. It checks if an object of the type provided in the argument could be assigned to the type against which the method is called, as in the following two examples:

typeof(IEnumerable).IsAssignableFrom(typeof(IList))  // true
typeof(IList).IsAssignableFrom(typeof(IEnumerable))  // false

To demonstrate the use of the method, let's create a hierarchy of types containing interfaces and classes. We'll then loop through all of the types in the assembly and see which implement a specific interface. This can be useful when developing software that uses plug-ins because it lets you find classes that third parties have created that are compatible with types in the main application.

Create a new console application and add the following types:

public interface IDataObject
{
    void Load();
    void Save();
}

public interface IIdBasedDataObject : IDataObject
{
    int Id { get; set; }
}

public interface INamedDataObject : IDataObject
{
    string Name { get; set; }
}

public interface IStandardDataObject : IIdBasedDataObject, INamedDataObject
{
}

public interface IUnrelated
{
}

public class Employee : IStandardDataObject
{
    public int Id { get; set; }

    public string Name { get; set; }

    public void Load()
    {
        // Code here
    }

    public void Save()
    {
        // Code here
    }
}

public class Manager : Employee
{
}

The above code contains several interfaces and classes. The relationships between them are pictured in the simple UML diagram below:

Hierarchy of interfaces and classes

Let's use the Main method of the console application to reflect over the types. The code below first obtains the IDataObject type, then retrieves all of the types in the assembly. The foreach loop processes each type in turn, outputting a message that indicates whether or not the type can be assigned into an IDataObject variable.

Type dataObjectType = typeof(IDataObject);
Assembly thisAssembly = Assembly.GetExecutingAssembly();
Type[] types = thisAssembly.GetTypes();

foreach (Type t in types)
{
    bool isAssignable = dataObjectType.IsAssignableFrom(t);
    Console.WriteLine("An object of {0} CAN {1}be assigned to an object of IDataObject"
        , t.Name, isAssignable ? "" : "NOT ");
}

Run the program to see the results.

An object of Program CAN NOT be assigned to an object of IDataObject
An object of IDataObject CAN be assigned to an object of IDataObject
An object of IIdBasedDataObject CAN be assigned to an object of IDataObject
An object of INamedDataObject CAN be assigned to an object of IDataObject
An object of IStandardDataObject CAN be assigned to an object of IDataObject
An object of IUnrelated CAN NOT be assigned to an object of IDataObject
An object of Employee CAN be assigned to an object of IDataObject
An object of Manager CAN be assigned to an object of IDataObject
27 March 2016