【问题标题】:Polymorphism in generics - compile error when passing inherited object (Cannot implicitly convert type)泛型中的多态性 - 传递继承对象时编译错误(不能隐式转换类型)
【发布时间】:2013-07-30 13:59:27
【问题描述】:

以下代码无法编译:

protected override ITaskScheduleAlgorithm<CollectionTask, ICoordinationExecutionService<CollectionTask>> GetAlgorithm()
{
    return new SimpleTaskScheduleAlgorithm<CollectionTask, WorkerServiceConfiguration>();
}

错误是:

无法隐式转换类型...

无法转换的类型:

WorkerServiceConfiguration → ICoordinationExecutionService

虽然类 WorkerServiceConfiguration 继承自 ICoordinationExecutionService:

public class WorkerServiceConfiguration : AbstractServiceConfiguration<CollectionTask>
{
...
}

public abstract class AbstractServiceConfiguration<TTask> : ICoordinationExecutionService<TTask>
{
...
}

知道为什么会发生这种情况以及如何解决吗?

【问题讨论】:

    标签: c# inheritance polymorphism


    【解决方案1】:

    我认为你有太多的泛型层,它变得令人困惑。实际答案在底部,但首先是题外话来解释问题...

    您是正确的,WorkerServiceConfiguration 继承自 ICoordinationExecutionService。这就是这段代码起作用的原因:

    protected ICoordinationExecutionService<CollectionTask> Test()
    {
        return new WorkerServiceConfiguration();
    }
    

    但是,您不会返回 ICoordinationService。您正在返回 ITaskScheduleAlgorithm。忽略第二个是ICoordinationExecutionService,你只关心这个接口声明。其实为了理解问题,让我们进一步简化一下:

    public interface ITaskScheduleAlgorithm<TType>
    {
    }
    
    public class SimpleTaskScheduleAlgorithm<TType> : ITaskScheduleAlgorithm<TType>
    {
    }
    
    public ITaskScheduleAlgorithm<object> GetAlgorithm()
    {
        return new SimpleTaskScheduleAlgorithm<string>();
    }
    

    如果您尝试运行这个简化的示例,您将得到完全相同的错误。您知道字符串派生自对象,因此您会期望多态性这应该有效。然而,仅仅因为字符串派生自对象并不意味着 SimpleTaskScheduleAlgorithm 实现了 ITaskScheduleAlgorithm。这取决于具体实现了哪些泛型方法。以 List 为例 - 即使字符串派生自对象,您也不能将新对象添加到 List。

    为了完成这项工作,您需要在接口声明中添加“out”关键字。对于我们的简单案例:

    公共接口 ITaskScheduleAlgorithm { }

    这表明接口是协变的(参见covariance and contravariance in generics)。请注意,如果接口没有接受泛型类型实例作为参数的方法,则只能使接口协变。因此,您的问题的最终答案是为您的 ITaskScheduleAlgorithm 接口添加协变支持:

    public interface ITaskScheduleAlgorithm<TType, out TType2>
    {
    }
    

    【讨论】:

      【解决方案2】:

      你应该这样做

      protected override ITaskScheduleAlgorithm<CollectionTask, ICoordinationExecutionService<CollectionTask>> GetAlgorithm()
      {
          return new SimpleTaskScheduleAlgorithm<CollectionTask, ICoordinationExecutionService<CollectionTask>>();
      }
      

      那么就可以使用WorkerServiceConfiguration类型的对象了

      【讨论】:

      • 在上面的例子中没有类/接口 CoordinationExecutionService。我无法理解您的建议。
      • 对不起,我已经编辑过了,我在CoordinationExecutionService之前错过了I,所以应该有ICoordinationExecutionService
      • 我知道这可以工作,但为什么我的代码是错误的?那是最初的问题..
      • 这是 C# 中的协方差限制,引用和实例应该具有相同的泛型类型。抱歉,我真的不知道更多。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-23
      • 1970-01-01
      • 2017-11-21
      • 2014-08-12
      • 2018-01-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多