I’ve got this setup in my code:
public abstract class ModelBase{}
public interface IModelbase<T>{}
public abstract class ModelBase<T> : ModelBase, IModelBase<T> {}
public class MyClass : ModelBase<int> {}
And then later I’m given a FutureValue<MyClass> object by NHibernate, and I try to:
if (obj is IFutureValue<ModelBase>) // => false?
// or
if (obj is FutureValue<ModelBase>) // => false?
// (I changed NHibernate's source to make FutureValue public, for other uses)
Meanwhile, if I cast it to the type directly:
if (((IFutureValue<MyClass>)obj).Value is ModelBase) // => true!
// or
if (((FutureValue<MyClass>)obj).Value is ModelBase) // => true!
… seriously? It’s in the inheritance chain, is there some reason it isn’t looking up it? Inspecting the object in the debugger shows it is in fact MyClass, and does have ModelBase methods and properties on it, so I doubt it has anything to do with NHibernate’s proxying.
Why would .NET not look up the inheritance chains in such a situation? Is there some keyword / casting trick I can perform to get it to do so? Or do I have to resort to a large, clunky setup similar to:
if (obj is IFutureValue<MyClass>) return ((IFutureValue<MyClass>)obj).Value;
if (obj is IFutureValue<MyOtherClass>) return ((IFutureValue<MyOtherClass>)obj).Value;
// etc etc ad infinitum
edit: this is in .NET 2.0
edit2: the exact code of (I)FutureValue:
public interface IFutureValue<T>
{
T Value { get; }
}
public class FutureValue<T> : IFutureValue<T>
{
public delegate IList<T> GetResult();
private readonly GetResult getResult;
public FutureValue(GetResult result)
{
getResult = result;
}
public T Value
{
get
{
var result = getResult();
if (result.Count == 0)
{
return default(T);
}
return result[0];
}
}
}
Am I just hugely misunderstanding the covariance / contravariance issue (in which case, why can Func<Type2, Type2> f1 = MyMethod; be cast to Func<Type3, Type1> f2 = f1; (where the first type is the return type) but the above code cannot do the same? Unless it’s just .NET 2.0 being lame with polymorphism?
edit3: thinking while typing. Is this case because IList<T> defines delegates which take, say, Derived type, therefore need Derived or DoublyDerived T, but the return type can only be T or Base? So I can’t cast either direction… I wonder if I can convince NHibernate to switch to IEnumerable<T> in their Futures… would that solve it?
IFutureValue<T>is a generic interface with a Covariant Type-parameter. You seem to be expecting the behavior of a Contravariant generic type parameter. For more information, read the MSDN documentation on Covariance and Contravariance in Generics