声明泛型基类型的变量,当继承类型具有不同的类型参数时

时间:2011-05-18 15:12:48

标签: c# .net generics

我有一个类层次结构,类似于:

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>
}

问题是,对于这样的类层次结构,我不能声明一个变量,它可以包含CCInfo和UCInfo类的实例(因为它们使用具有不同类型参数的基类型)。据我所知 - 我也不能使用方差,因为我的泛型参数既用于输入也用于输出。

我个人在这里感觉到某种反模式,但是无法弄清楚如何解决这个问题。

2 个答案:

答案 0 :(得分:4)

您可以创建非泛型基类或接口,也可以使用协变泛型接口(要求属性只读)。

答案 1 :(得分:2)

设计确实依赖于您想要达到的目的。 如果您希望单个变量能够存储CCInfo和UCInfo类的实例,则此变量将只能看到这两种类型的共同点。 在我看来,唯一可行的是CCInfo或UCInfo无论是访问提出的决策和finalDecision,都被视为BaseDecision实例(如果你想保持通用,那就更精确了)。 因此,在此上下文中,将读取这些属性(是“out属性”)。 因此,您可以通过这种方式依赖协方差:

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> 
    }
}

当然可以编译。现在,您可以查看这段代码是否可以在您的特定环境中重复使用,以实现您的目标......祝您好运!