Declaring a variable of generic base type, when inheriting types have different type parameters
I have a class hierarchy, which is something like that:
public abstract class BaseDecision
{
// <implementation>
}
public class CCDecision : BaseDecision
{
// <implementation>
}
public class UCDecision : BaseDecision
{
// <implementation>
}
public abstract class BaseInfo<TDecision> where TDecision:BaseDecision, new()
{
public TDecision proposedDecision;
public TDecision finalDecision;
// <implementation>
}
public class CCInfo : BaseInfo<CCDecision>
{
// <implementation>
}
public class UCInfo : BaseInfo<UCDecision>
{
// <implementation>
}
The problem is, that with such a class hierarchy, I can't declare a variable, which could contain instances of both CCInfo and UCIn开发者_StackOverflow社区fo classes (as they use a base type with a different type parameter). As far as I understand - I can't make use of variance either, as my generic parameter is used both for input and for output.
I personally sense some kind of anti-pattern here, but just can't figure out how to solve this.
You can either make a non-generic base class or interface, or use a covariant generic interface (which requires that the properties be readonly).
The design really relies on the purpose you want to achieve. If you want a single variable able to store instances of both CCInfo and UCInfo classes, this variable will be able to see only what is common to these 2 types. It seems to me that the only thing feasible which would be the same whatever it's a CCInfo or UCInfo is accessing to proposedDecision and finalDecision, seen as BaseDecision instances (nothing more precise if you want to remain generic). So in this context these properties are read (are "out properties"). Thus you can rely on covariance this way :
class Program
{
public static void Main(string[] args)
{
CCInfo ccInfo = new CCInfo();
UCInfo ucInfo = new UCInfo();
IBaseInfo<BaseDecision> x = ccInfo;
x = ucInfo;
}
public class BaseDecision
{
// <implementation>
}
public class CCDecision : BaseDecision
{
// <implementation>
}
public class UCDecision : BaseDecision
{
// <implementation>
}
public interface IBaseInfo<out TDecision> where TDecision : BaseDecision, new()
{
TDecision proposedDecision { get; }
TDecision finalDecision { get; }
}
public abstract class BaseInfo<TDecision> : IBaseInfo<TDecision> where TDecision : BaseDecision, new()
{
public TDecision proposedDecision { get; set; }
public TDecision finalDecision { get; set; }
// <implementation>
}
public class CCInfo : BaseInfo<CCDecision>
{
// <implementation>
}
public class UCInfo : BaseInfo<UCDecision>
{
// <implementation>
}
}
Sure it compiles. Now it's up to you to see if this piece of code is reusable in your specific context to achieve your goals... Good luck !
精彩评论