Search code examples
c#inheritanceinterfacecontravariance

Contravariance in C#


I have a problem with contra-variant interfaces and am not sure the best way to solve it. These are my classes:

public interface IObject {
}
public interface IBigObject : IObject {
}
public interface ISmallObject : IObject {
}
public class AnObject : IBigObject {

} 
public class DataWrapper<T> {
    public T Data { get; set; }
} 

I want to be able to pass a DataWrapper<IObject> (which could be a number of derived classes) and get at the item as an IObject, and the only way I can do this as far as I can see is like this:

IObject itemToAdd = null;
if (values[1] is IObject) {
    itemToAdd = values[1] as IObject;
} else if (values[1] is DataWrapper<IObject>) {
    itemToAdd = ((DataWrapper<IObject>)values[1]).Data;
} else if (values[1] is DataWrapper<IBigObject>) {
    itemToAdd = ((DataWrapper<IBigObject>)values[1]).Data;
} else if (values[1] is DataWrapper<BigObjectBase>) {
    itemToAdd = ((DataWrapper<ObservableBigObject>)values[1]).Data;
} else if (values[1] is DataWrapper<ObservableBigObject>) {
    itemToAdd = ((DataWrapper<ObservableBigObject>)values[1]).Data;
} 

Is there a shorter way?


Solution

  • Classes cannot have variance in C#, so you'll have to create an interface e.g.

    public interface IObjectWrapper<out T> where T : IObject
    {
        T Value { get; }
    }
    

    Then you should be able to do

    if(values[1] is IObjectWrapper<IObject>)
    {
        itemToAdd = ((IObjectWrapper<IObject>)values[1]).Value;
    }
    

    If you don't want to do that, you could use reflection:

    Type t = values[1].GetType();
    if(t.IsGenericType && 
        t.GetGenericTypeDefinition() == typeof(DataWrapper<>) && 
        typeof(IObject).IsAssignableFrom(t.GetGenericArguments()[0]))
    {
        itemToAdd = (IObject)t.GetProperty("Data").GetValue(value[0], null)
    }