c#中的子级到父级泛型转换

时间:2014-06-16 11:02:19

标签: c# generics covariance contravariance

我有我的基础接口类:

 public interface IAlgorithm<T> where T : IParams
 {
        /// <summary>
        /// Contains algorythm parameters
        /// </summary>
        T Params{ get; set; }
 }

并且

public interface IParams
{
}

然后我有了算法实现的基本类:

public abstract class BaseAlgorithm<T> : IAlgorithm<T> where T: IParams
{
    public virtual T Params { get; set; }
}

 public class DataAlgorithm : BaseAlgorithm<IDataParams>
 {
        public override IDataParams Params { get; set; }
 }

并且参数:

public interface IDataParams : IParams
{
}

有多个BaseAlgorithm类实现。

现在我想创建DataAlgorith的新isntance并将其分配给父接口:

IAlgorithm<IParams> algorithm = new DataAlgorithm();

但它不会工作并产生错误消息:

Cannot implicitly convert type 'DataAlgorithm' to 'IAlgorithm<IParams>'. An explicit conversion exists (are you missing a cast?)

以下代码可以正常使用:

IAlgorithm<IDataParams> algorithm = new DataAlgorithm();

如何分配父类型的任何想法?

2 个答案:

答案 0 :(得分:3)

您不能这样做,因为DataAlgorithmIAlgorithm<IDataParams>,而不是IAlgorithm<IParams>

想一想。如果是的话,你就能做到

IAlgorithm<IParams> algorithm = new DataAlgorithm();

algorithm.Params = ... some other kind of IParams but not IDataParams.

显然,这没有任何意义。

如果对象是IAlgorithm<IParams>,则意味着您可以将实现IParams的任何对象分配给其Params属性。实现IAlgorithm<IDataParams>的对象不是这种情况,因为它只接受IDataParams setter中Params的实现。因此,IAlgorithm<IDataParams>不是IAlgorithm<IParams>

但是,如果不需要Params属性的setter,则可以使接口协变。

public interface IAlgorithm<out T> where T : IParams
{
    /// <summary>
    /// Contains algorythm parameters
    /// </summary>
    T Params{ get; }
}

相应地调整基类。

答案 1 :(得分:1)

要扩展Kris的上述答案check out the article on covariance and contravariance on MSDN

为了简单起见,而不是IAlgorithm<IDataParams>,想象一下List<IParams>。任何实现IParams的类型都应该能够存储在该列表中。但是,请想象以下代码:

    List<IParams> lst = new List<IDataParams>();
    lst.Add(new ClassImplementingIParamButNotIDataParams());

由于List<IDataParams>只接受IDataParams,后一种说法无效。但是,List<IDataParams> lst = new List<IParams>(); 有效:可以添加到列表中的所有IDataParams也将是IParams

这只是一个例子;正如Kris所说,您可以使用通用的inout关键字来控制类型参数的协方差/逆变。 MSDN文章是一个良好的开端。