【问题标题】:Overloading method without modifying classes重载方法而不修改类
【发布时间】:2019-03-27 14:40:35
【问题描述】:

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

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) ...

或创建一个字典来降低每种类型的复杂性,但这并不是最好的处理方式


我的考虑

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

我查看了双重调度和访问者模式,但我不确定它们是否满足我的要求,因为它们看起来我必须修改这些类(或者我可能只是没有完全理解它们),并且(有点但是很明显)泛型也基本上不在窗口中,因为它们需要我提前知道这是什么类型的 Graphics 对象。


那么两个问题:

除了使用一些字典或其他if (g is Type)-like 之外,还有更好的方法吗?

如果我可以修改类,模式会是什么样子?在这种情况下这是不可能的,但是在我可以的情况下,双重调度/访问者是最好的方式吗?

【问题讨论】:

  • 如果您可以修改类型,您将添加一个虚拟/抽象 ToJson 实例方法并根据需要进行覆盖。使用反射来找到 ToJson 代码的正确实现的“规则引擎”可能是最好的方法。
  • 所以,是的,一个实现这个的委托/对象类型的字典可能是我自己选择的。
  • 装饰器模式?
  • 正如您所注意到的,要使用访问者模式进行双重调度,您需要“已访问”类来实现一个方法,该方法在适当的方法上调用“访问者”类。我在这里举一个简单的例子:ericlippert.com/2015/05/04/wizards-and-warriors-part-three 当你有一组相关的对象时,你通常会使用访问者模式,你需要对这些对象执行各种分析或转换通道,每个操作的确切细节取决于both 访问对象和访问者对象的运行时类型。
  • 感谢您的意见 Eric - 我会读一读! ??????

标签: c# inheritance overloading visitor-pattern double-dispatch


【解决方案1】:

无法修改基类,或者在具体类型变成泛型Graphics 类型之前访问它,不幸的是,我认为除了检查@987654322 的运行时类型之外,您无能为力@对象。

您可以使用 switch 语句(从 C# 7.0 开始),它比您的 if 链稍微干净一些:

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

就我个人而言,我认为使用 Dictionary 相对于这样的 switch 语句并没有太大的优势 - 两者都可以放入一个独立的小方法中(因此可以减少 amount开/关原则),但开关会便宜得多。

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

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

...虽然,动态有相当大的运行时间成本,并且通常被认为是气味。

【讨论】:

  • switch 正在使用某种模式匹配?我不知道 C# 中的 switch 语句可以做到这一点! :)
  • @Nick 是的,从 C# 7.0 开始
  • 天哪,好久不见了。上次用C#还是5.0,感觉老了
  • 公平地说,自 5.0 以来没有发生任何突破性的事情(除了 Roslyn) - 有很多小的改进。不过,C# 8 将再次取得突破性进展
猜你喜欢
  • 2014-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-18
  • 1970-01-01
相关资源
最近更新 更多