C# 将实际对象类型发送到重载函数 请考虑以下情况

C# 将实际对象类型发送到重载函数 请考虑以下情况,c#,inheritance,polymorphism,type-conversion,C#,Inheritance,Polymorphism,Type Conversion,我有一个类型为“Shapes”的超级类和继承形状的类“Box”、“Circle”和“Arrow”。我在其他地方有一个形状列表,可以包含这些类型的任何成员。我需要列举清单并画出每个形状。问题是每个形状的绘制方式不同,因此我有: void Draw(Box b) {} void Draw(Square s) {} void Draw(Circle c) {} 问题是,当我枚举列表时,返回的每个元素都是Shape类型(因为列表是Shape类型),即使它的实际类型可能是Box。因此,没有一个重载被

我有一个类型为“Shapes”的超级类和继承形状的类“Box”、“Circle”和“Arrow”。我在其他地方有一个形状列表,可以包含这些类型的任何成员。我需要列举清单并画出每个形状。问题是每个形状的绘制方式不同,因此我有:

void Draw(Box b) {}

void Draw(Square s) {}

void Draw(Circle c) {}
问题是,当我枚举列表时,返回的每个元素都是Shape类型(因为列表是Shape类型),即使它的实际类型可能是Box。因此,没有一个重载被认为是正确的

我的一个想法是创建一个临时对象,并将其声明为列表元素的实际类型。所以,让我们假设列表[i]是圆的类型

object o = Type.GetType(Convert.ToString(list[i].GetType()));
o = list[i];
但这仍然不起作用,因为现在编译器将“o”的类型识别为Object而不是Circle

我怎样才能避开这个问题

void Draw(Shapes s) 
{ 
   if (s is Circle) 
   {
      Draw((Circle)s);
   }
}

依此类推。

Shape
类中创建一个抽象的
Draw
方法。在每个派生类中重写它。让特定的形状自己画


例如:

public interface IDrawingSurface {
    // All your favorite graphics primitives
}

public abstract class Shape {
    public abstract void Draw();

    protected IDrawingSurface Surface {get;set;}

    public Shape(IDrawingSurface surface) {
        Surface = surface;
    }
}

public class Box {
    public Box(IDrawingSurface surface) : base(surface) {}
    public virtual void Draw(){ Surface.Something();... }
}

public class Square {
    public Square(IDrawingSurface surface) : base(surface) {}
    public virtual void Draw(){ Surface.Something();... }
}

public class Circle {
    public Circle(IDrawingSurface surface) : base(surface) {}
    public virtual void Draw(){ Surface.Something();... }
}

更好的解决方案是在shape
Draw()
上使用
abstract
函数,然后在Box、Circle和Sqaure中重写该函数。

为什么不在shape上使用Draw虚拟方法,然后在每个派生类上重写它呢?然后你可以这样做:

List<Shapes> shapes = ... get your list of shapes somewhere ...

foreach (var shape in shapes) {
    shape.Draw();
}
列表形状=。。。在某处获取您的形状列表。。。
foreach(形状中的变量形状){
shape.Draw();
}
将对特定派生类调用正确的虚方法。这是多态性的教科书案例

公共接口IShape
public interface IShape
{
     public void Draw();
}

public class Circle : IShape
{
    public void Draw()
    {
      do somethig shape specific
    }

}

List<IShape> shapes

foreach (IShape shape in shapes)
{
     shape.Draw();
}
{ 公众提款(); } 公共阶级圈子:IShape { 公众抽签() { 做一些特定形状的事情 } } 列表形状 foreach(形状中的IShape形状) { shape.Draw(); }
我个人会按照建议使用一个接口,但如果您无法访问呼叫您的用户(如第三方.dll),则可以接受object类型的参数:

    /// <summary>
    /// Draw any type of object if the objec type is supported.
    /// Circles, Squares, etc.
    /// </summary>
    /// <param name="objectToDraw"></param>
    public void Draw(object objectToDraw)
    {
        // get the type of object
        string type = objectToDraw.GetType().ToString();

        switch(type)
        {
            case "Circle":

                // cast the objectToDraw as a Circle
                Circle circle = objectToDraw as Circle;

                // if the cast was successful
                if (circle != null)
                {
                    // draw the circle
                    circle.Draw();
                }

                // required
                break;

            case "Square":

                // cast the object as a square
                Square square = objectToDraw as Square;

                // if the square exists
                if (square != null)
                {
                    // draw the square
                    square.Draw();
                }

                // required
                break;

            default:

                // raise an error
                throw new Exception("Object Type Not Supported in Draw method");
        }
    }
//
///如果支持objec类型,则绘制任何类型的对象。
///圆、正方形等。
/// 
/// 
公共无效绘图(对象objectToDraw)
{
//获取对象的类型
字符串类型=objectToDraw.GetType().ToString();
开关(类型)
{
案例“圆圈”:
//将objectToDraw投射为一个圆
圆圈=对象绘制为圆圈;
//如果演员阵容成功
如果(圆圈!=null)
{
//画圆圈
画圆();
}
//必需的
打破
案例“方形”:
//将对象投射为正方形
Square Square=对象绘制为正方形;
//如果正方形存在
如果(平方!=null)
{
//画正方形
正方形。画();
}
//必需的
打破
违约:
//出错
抛出新异常(“Draw方法中不支持对象类型”);
}
}
在Box类上绘制的方式是错误的。Box类应该只有Draw()方法

若要使用“图形类型列表”进行绘图,则必须确保已在派生类中重写Draw方法

您标记为已接受的答案详细说明了这一点


另外,为了获取信息,绘制(框b)适合静态方法类别。

+1。或者使用一个接口,比如
IDrawable
,并让可以绘制的子类实现该接口。这是我的第二个想法,它肯定会起作用。我最恼火的是,我创建的任何控件都必须传入对pictureBox的引用才能绘制。我希望找到一种摆脱它的方法。将PictureBox推广到
IDrawingSurface
界面,那么至少你不会依赖于特定的绘图技术。您还可以将该接口传递到形状的构造函数中,这样就不需要在每次
Draw
调用中传递该接口。由其他形状组成的形状可以将其自身的
IDrawingSurface
引用传递给组件形状,也就是说,“绘制到我绘制到的同一位置”。虽然可以这样做,但这比我在之前的回答中建议的虚拟方法要昂贵得多。这里的方法需要将反射分派到正确的方法,这会很慢。当然,但如果OP不想更改其形状,这是另一种方法。谢谢,这绝对是一种解决方案,但我避免了通过if-else阶梯来找出对象的实际类型。我觉得这有点否定了多态性的全部观点,不是吗?
void Draw(Box b) {}