Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将泛型实例添加到泛型对象列表_C#_Oop_Generics_Inheritance_Polymorphism - Fatal编程技术网

C# 如何将泛型实例添加到泛型对象列表

C# 如何将泛型实例添加到泛型对象列表,c#,oop,generics,inheritance,polymorphism,C#,Oop,Generics,Inheritance,Polymorphism,我有一个界面IShape和抽象类形状。形状实现了IShape。形状有两个子元素-圆形和矩形。 我还有通用接口IDrawer,其中T:IShape。我有一个抽象的泛型类BaseDrawer:IDrawer,其中T:IShape public interface IShape { double M1(); double M2(); } public abstract class Shape : IShape { public

我有一个界面IShape和抽象类形状。形状实现了IShape。形状有两个子元素-圆形和矩形。 我还有通用接口IDrawer,其中T:IShape。我有一个抽象的泛型类BaseDrawer:IDrawer,其中T:IShape

public interface IShape
    {
        double M1();
        double M2();
    }

public abstract class Shape : IShape
    {
        public abstract double M1();
        public abstract double M2();
    }

public class Circle : Shape
    {
    }

public class Rectangle: Shape
    {
    }

public interface IDrawer<T> where T:IShape
    {
        void Draw(T shape);
    }  

 public abstract class BaseDrawer<T> : IDrawer<T> where T : IShape
    {
       public abstract void Draw(T shape);
    }

public class CircleDrawer : BaseDrawer<Circle>
    {
        public override void Draw(Circle circle)
        {
        }
    }

public class RectangleDrawer : BaseDrawer<Rectangle>
        {
            public override void Draw(Rectangle rectangle)
            {
            }
        }
公共接口IShape
{
双M1();
双M2();
}
公共抽象类形状:IShape
{
公开摘要双M1();
公共抽象双M2();
}
公共课圈:形状
{
}
公共类矩形:形状
{
}
公共接口IDrawer,其中T:IShape
{
空洞拉伸(T形);
}  
公共抽象类BaseDrawer:IDrawer其中T:IShape
{
公共抽象空图(T形);
}
公共类CircleDrawer:BaseDrawer
{
公共覆盖无效绘制(圆)
{
}
}
公共类矩形抽屉:BaseDrawer
{
公共替代无效图形(矩形)
{
}
}
我有一个列表:
列出抽屉{get;set;}
当我试图创建CircleDrawer的实例时-
var drawer=new CircleDrawer()-并将其添加到此列表中,我得到一个错误:无法将CircleDrawer转换为IDrawer


要将circleDrawer实例添加到此列表中,我需要做哪些更改?

通用协方差和反协方差我们开始吧

因此,我们可以直接将
CircleDrawer
类型转换为
IDrawer
。让我们看看会发生什么

var list = new List<IDrawer<IShape>>();
IDrawer<Circle> drawer = new CircleDrawer(); // Completely reasonable cast.

list.Add(drawer); // This results in the error.
现在我们在其他地方把它从列表中去掉,给它一个形状:

IDrawer<IShape> drawer = list.First();
drawer.Draw(shape);
然后是的,我们给我们的
圈绘者画了一个圈,一切都很好。但请注意这一行:

IShape shape = new Rectangle();

drawer.Draw(shape);
也将是合法的。应该是这样的,给
IDrawer
一个
IShape
对象似乎是合理的。感觉应该有用。但事实并非如此。您刚才调用了一个
CircleDrawer.Draw(Circle shape)
方法,方法是用一个矩形代替圆。会发生什么?这不是任何
CircleDrawer
都希望遇到的情况。想象一下,如果你一生都被教如何画圆圈,突然有人给你一个长方形来画:O

因此,类型系统不允许在列表中添加
。通常,当这种情况发生时,您可以通过将泛型类型标记为co-或逆变来修复它。但在这种情况下,你想做的事情实际上是不可能的和荒谬的——一系列你不知道确切类型的抽屉对你来说毫无用处。你不知道他们会画什么,所以每次打
draw
电话,你都在玩俄罗斯轮盘赌,希望你刚才传递的矩形是一个
RectangleDrawer
而不是一个
CircleDrawer

你唯一能做的事情就是用另一种方式分配事物——比如说你有一个
矩形抽屉
和一个
方形抽屉

class Rectangle : IShape {}

class Square : Rectangle {}

class RectangleDrawer : IDrawer<Rectangle> {}

class SquareDrawer : IDrawer<Square> {}
这告诉编译器如果
U:T
,则
IDrawer
也可以绘制
U
。它还不允许将
T
指定为任何成员方法的返回类型


更多关于协方差和逆变换的信息可以找到。

让我们考虑一下这个问题

你是说
圆圈绘图器
IDrawer
的一种,因为
圆圈
IShape
的一种

但是
IDrawer
可以绘制
IShape
——任何
IShape
。现在,
CircleDrawer
可以画一个圆,但不能画其他形状,因此它不是
IDrawer

然而,
IDrawer
理论上可以是
IDrawer
的实例,因为它可以绘制任何形状,包括圆。要正式指定,您必须使用协方差/反方差:

在您的情况下,恐怕您必须创建一个
列表

如果您被允许处理一个<代码>循环抽屉>代码> <代码> IDrawer <代码>,请考虑下面的代码:

IDrawer<IShape> drawer = new CircleDrawer();
drawer.Draw(new Rectangle()); //Throws exception - a circle drawer can't draw a rectangle
IDrawer drawer=new CircleDrawer();
drawer.Draw(新矩形())//抛出异常-圆形抽屉无法绘制矩形
IShape shape = new Rectangle();

drawer.Draw(shape);
class Rectangle : IShape {}

class Square : Rectangle {}

class RectangleDrawer : IDrawer<Rectangle> {}

class SquareDrawer : IDrawer<Square> {}
var list = new List<SquareDrawer>();

var squareDrawer = new SquareDrawer();
var rectangleDrawer = new RectangleDrawer();

list.Add(squareDrawer);
list.Add(rectangleDrawer);
interface IDrawer<in T> where T : IShape
{
    void Draw(T shape);
}
IDrawer<IShape> drawer = new CircleDrawer();
drawer.Draw(new Rectangle()); //Throws exception - a circle drawer can't draw a rectangle