无需修改类的重载方法

时间:2019-03-27 14:40:36

标签: c# inheritance overloading visitor double-dispatch

我可以访问无法修改的类结构,如下所示:

Graphics
  Circle
  Line
  etc.

同样,我无法修改!这些都有单独的属性,例如RadiusFirstPointLastPoint等,以及一些常见的属性。

我想创建一个接受Graphics对象的方法,并根据对象的类型运行一个ToJson方法:

Graphics g = db.GetGraphic(123);
// Console.WriteLine(g.GetType()) prints "Circle"

// Should run some specific implementation for `Circle` type graphics, and
// have an overload for all types including Graphics
ToJson(g);

起初我以为我可以巧妙地重载ToJson方法:

ToJson(Graphics g) { ... }
ToJson(Circle g) { ... }
ToJson(Line g) { ... }

但这当然每次都会导致通用ToJson(Graphics)超载。

我确定我可以执行以下操作:

if (g is Circle) ...
if (g is Line) ...
if (g is Graphics) ...

或创建一个Dictionary来降低每种类型的复杂性,但这并不像是做事的最佳方式


我考虑过的

我考虑过是否可以在每个对象周围使用某种通用包装方法(例如new JsonGraphics(g).ToJson()),但是我不想自己进行任何手动类型检查。

我已经研究了双重调度和访问者模式,但是我不确定它们是否满足我的要求,因为它们看起来像我必须修改这些类(或者也许我只是不完全理解它们),以及显然,)泛型也基本上不在窗口之内,因为它们要求我提前知道这是什么类型的Graphics对象。


然后有两个问题:

除了使用一些Dictionary或其他类似if (g is Type)的东西之外,还有其他更好的方法吗?

如果我可以修改类,则模式将如何显示?在这种情况下这是不可能的,但是在可能的情况下,双重派遣/访客是否是最好的选择?

1 个答案:

答案 0 :(得分:2)

由于无法修改基类,也无法在将具体类型转换为通用Graphics类型之前对其进行访问,很遗憾,除了检查运行时类型之外,我认为您无法做任何其他事情Graphics个对象。

您可以使用switch语句(自C#7.0起),它比您的if链要干净一些:

switch (g)
{
    case Circle circle: ... break;
    case Line line: ... break;
    default: /* Oh no! */ break;
}

就这样的switch语句,我个人认为使用Dictionary并没有太大优势-两者都可以放在一个独立的方法中(这样可以减少违反的 amount (打开/关闭原理),但开关价格会便宜得多。

您还可以使用dynamic,这会导致运行时进行后期绑定:

dynamic d = g;
ToJson(d); // Picks the right ToJson overload corresponding to the runtime type of 'd'

...但是,动态具有相当大的运行时成本,通常被认为是气味。