在Asp.net中,您如何将子类呈现给html帮助器?

时间:2011-01-19 21:02:31

标签: c# asp.net oop

如何使用TriangleExtension和SquareExtension辅助方法渲染我的Document类?

这是我的示例设置:

public class Document
{
    public List<Shape> Shapes = new List<Shape>();
    public Document()
    {
        Shapes.Add(new Triangle());
        Shapes.Add(new Square());
    }   
}

public abstract class Shape
{
    int width = 5;
}

public class Triangle : Shape
{
    int height = 10;
}

public class Square : Shape
{
    int height = 10;
}

我将一个Document对象传递给我的视图,并希望将其呈现为:

foreach (var shape in Model.Shapes)
{
    //what code do I put here?
    //e.g. if (shape.GetType=="Triangle")
    //        Helper.Triangle(shape)
    //     if (shape.getTYpe=="Square")
    //        Helper.Square(shape)
}

编辑:这个问题是另一种询问我真正想问的问题:ASP.net MVC - rendering a List containing different types, with a different view for each type

1 个答案:

答案 0 :(得分:4)

很难确切地告诉您要做什么,但您的示例代码会违反Liskov替换委托人。您的渲染方法应该适用于传入的每个和任何形状。因此,如果以后添加平行四边形,则无需更改页面逻辑。它应该工作,因为它是一个形状。

以下代码之类的东西可以帮到你。

public interface IShapeRenderer
{
    void DrawLine(int x1, int y1, int x2, int y2);
}

public abstract class Shape
{
    public abstract void Render(IShapeRenderer renderer);
}

public class Triangle: Shape
{
    public override void Render(IShapeRenderer renderer)
    {
        // draw 3 lines
    }
}

public class Square: Shape
{
    public override void Render(IShapeRenderer renderer)
    {
        // draw 4 lines
    }
}

public class HtmlRenderer: IShapeRenderer
 {
    public void DrawLine(int x1, int y1, int x2, int y2)
    {
        // draw html line
    }
 }

然后你的渲染外观可能如下所示:

  var renderer = new HtmlRenderer();
  foreach (var shape in shapes)
  {
    shape.Render(renderer);
  }

现在,您创建的每个形状都需要知道如何使用渲染器提供的指令来创建自身。只要为其创建渲染器,就可以渲染Html或图像或​​ascii art。

另一种选择是做类似GetEnumerator()如何处理集合的内容,并包含一个知道如何绘制的内部私有类。然后,您可以将形状设置为GetDrawInstructions()并使用渲染器。这样,您的形状和绘图说明在单独的类中是单独的关注点。只是其中一个嵌套在另一个中。

public interface IDrawInstructions
{
    void Draw(IShapeRenderer renderer);
}

public abstract class Shape
{
    public abstract IDrawInstructions GetDrawInstructions();
}

public class Triangle: Shape
{
    public override IDrawInstructions GetDrawInstructions()
    {
        return new TriangleDrawInstructions(this);
    }

    private class TriangleDrawInstructions: IDrawInstructions
    {
        public Triangle Triangle { get; private set; }

        public TriangleDrawInstructions(Triangle triangle)
        {
            Triangle = triangle;
        }

        public void Draw(IShapeRenderer renderer)
        {
            // draw 3 lines using information from triangle
        }
    }
}

      var renderer = new HtmlRenderer();
      foreach (var shape in shapes)
      {
        var instructions = shape.GetDrawInstructions();
        instructions.Draw(renderer);
      }

最后一个选项是使用DrawInstructionsRegistry,并在注册表中注册每个形状的绘图说明,然后在需要时调用它。

public class ShapeDrawInstructionsRegistry
{
    private static Dictionary<Type, IDrawInstructions> _registry = new Dictionary<Type, IDrawInstructions>();

    public static void Register<T>(IDrawInstructions instructions) where T: Shape
    {
        var type = typeof (T);
        if(_registry.ContainsKey(type))
            _registry[type] = instructions;
        else
        {
            _registry.Add(type, instructions);
        }
    }

    public static IDrawInstructions Lookup(Shape shape)
    {
        var type = shape.GetType();
        if (!_registry.ContainsKey(type)) return null;
        return _registry[type];
    }
}

public class SquareDrawInstructions: IDrawInstructions
{
    public void Draw(Shape shape, IShapeRenderer renderer)
    {
        var square = shape as Square;
        if (square == null) throw new Exception();
        // draw 4 sides
    }
}



// in your global.asax.cs or bootstrapper class
ShapeDrawInstructionsRegistry.Register<Square>(new SquareDrawInstructions());
ShapeDrawInstructionsRegistry.Register<Triangle>(new TriangleDrawInstructions());

// your loop
var renderer = new HtmlRenderer();
foreach (var shape in shapes)
{
    var instructions = ShapeDrawInstructionsRegistry.Lookup(shape);
    instructions.Draw(shape, renderer);
}

其他选择可能会解决您的问题,但我认为这可能比它的价值更麻烦。