具有非多态子类和抽象的多态基类

时间:2019-01-30 14:25:15

标签: c# polymorphism

考虑一下,我有一个包含三个类的TemplateEngine:

  • TemplateEngine
  • TemplateBase<T> where T : TemplateDataBase
  • TemplateDataBase

和示例实现:

  • SampleTemplate : TemplateBase<SampleTemplateData>
  • SampleTemplateData : TemplateDataBase

现在,在引擎中,有一个吸气功能:

public T GetTemplate<T, U>() where T: TemplateBase<U>, new() where U : TemplateDataBase
{
    var template = new T();
    ...
    return template;
}

由于TemplateBase的所有实现都将为U恰好具有一个有效值,就像示例一样,可以通过选择U来推断T的类型,并且我不必将其提供给GetTemplate方法。

其他TemplateData类包含的数据完全不同,并且某个模板不能使用错误的TemplateData类。

如果现在从函数调用中删除U类型参数,则会得到“类型参数数目不正确”,或者,如果从函数定义中删除类型参数,则该吸气剂将不再有效,因为“无法解决U”。

如果保留该参数,则仍然不允许这样做,因为“没有从SampleTemplateTemplateBase<TemplateDataBase>的隐式引用转换”。

我在这里做什么错了?

1 个答案:

答案 0 :(得分:3)

由于您要尝试使用类型参数,而该类型参数是GetTemplate方法中定义的类型参数的子代,因此需要使用协变类型参数。根据定义

  

使您可以使用比最初指定的类型更多的派生类型

并且由于方差修改只能应用于接口或委托,因此您需要创建两者之一。这是一个使用generic interface with a covariant type parameter的示例,该示例允许您暗示类型参数:

interface ITemplate<out T> where T : TemplateDataBase
{
    Type DataType { get; }
}

class TemplateBase<T> : ITemplate<T> where T : TemplateDataBase
{
    public Type DataType => typeof(T);
}

class TemplateDataBase { }

class TemplateEngine
{
    public T GetTemplate<T>() where T : ITemplate<TemplateDataBase>, new()
    {
        var template = new T();
        return template;
    }
}

class SampleTemplate : TemplateBase<SampleTemplateData> { }

class SampleTemplateData : TemplateDataBase { }

请注意ITemplate<out T>。这实际上是说类型参数是协变的。

这是一个推断类型的使用站点的示例:

static void Main(string[] args)
{
    var engine = new TemplateEngine();
    var sampleTemplate = engine.GetTemplate<SampleTemplate>();

    Console.WriteLine($"{sampleTemplate.DataType.Name}");
    Console.ReadLine();
}

enter image description here