模板的通用错误

3
我正在尝试制作一个模板类列表,将基类传递给模板。然而,似乎这是不允许的。有没有办法规避这个限制,或者重新组织我的代码更加合适?
这里是一个抽象的例子:
using System;
using System.Collections.Generic;

namespace TempInherit
{
    abstract class Shape{}

    class Triangle : Shape{}
    class Square : Shape{}

    class ShapeHolder<T>{}

    class MainClass
    {
        public static void Main(string[] args)
        {
            // list of base class, add subclass - works
            List<Shape> shapes = new List<Shape>();
            shapes.Add(new Triangle());
            shapes.Add(new Square());

            // list of holders of base class, add holders of subclass - fails
            List<ShapeHolder<Shape>> shapeHolders = new List<ShapeHolder<Shape>>();
            shapeHolders.Add(new ShapeHolder<Triangle>());
            shapeHolders.Add(new ShapeHolder<Square>());
        }
    }
}

这段文字的意思是:
错误 CS1502:最佳重载方法匹配 `System.Collections.Generic.List>。Add(TempInherit.ShapeHolder)'存在一些无效参数(CS1502)(TempInherit)
错误 CS1503:参数#1'无法将` TempInherit.ShapeHolder '表达式转换为类型` TempInherit.ShapeHolder'(CS1503)(TempInherit)

你能提供更多关于ShapeHolder<T>和Shape的代码吗? - Dzmitry Martavoi
@DmitryMartovoi:我已经添加了完整的代码,但它只是一个小样本,模仿了我在真实应用程序中遇到的错误。我相信这是由于我对C#泛型的误解,因为我是一名iOS/Android开发人员,正在使用Xamarin进行尝试。 - Josh
原因是 ShapeHolder<Triangle> 没有被视为继承自 ShapeHolder<Shape>。 - Dan Hunex
我已经编辑了你的标题。请参考“问题的标题应该包含“标签”吗?”,在那里达成共识是“不应该”。 - John Saunders
1个回答

6

协变问题:

您可以创建一个接口IShapeHolder<out T>,因为接口上的泛型参数可以是协变的(但类上不行)

类似这样的东西

public class Shape
    {
    }
    public class Triangle : Shape
    {
    }
    public class Square : Shape
    {
    }
    //T generic parameter is covariant (out keyword)
    public interface IShapeHolder<out T> where T : Shape
    {
    }
    public class ShapeHolder<T>  : IShapeHolder<T> where T: Shape
    { 
    }

那么,
var shapes = new List<Shape>();
shapes.Add(new Triangle());
shapes.Add(new Square());

// list of holders of base class, add holders of subclass - fails no more
var shapeHolders = new List<IShapeHolder<Shape>>();
shapeHolders.Add(new ShapeHolder<Triangle>());
shapeHolders.Add(new ShapeHolder<Square>());

2
注意,这禁止从shapeHolder中检索项目。但这是有意设计的,否则您可能会通过将其转换为ShapeHolder<Shape>Square插入到ShapeHolder<Triangle>中。 - Dykam
@Josh Fine 如果有帮助的话,但请仔细阅读评论,它们是重要的缺点! - Raphaël Althaus
@RaphaëlAlthaus:我的ShapeHolder<T>实际上是FeedManager<T>,它们负责纯粹下载其各自的RSS源,并将XML编组为泛型参数的类型,因此我无需检索“holder”中的项目,只需迭代即可。 - Josh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接