C# 重载方法而不修改类

C# 重载方法而不修改类,c#,inheritance,overloading,visitor,double-dispatch,C#,Inheritance,Overloading,Visitor,Double Dispatch,我可以访问一个类结构,但我不能修改它,如下所示: Graphics Circle Line etc. 再说一遍,我不能修改它!这些都有单独的属性,如半径,第一点,最后点,以及一些常见属性 我想创建一个接受Graphics对象的方法,并根据对象的类型运行ToJson方法: Graphics g = db.GetGraphic(123); // Console.WriteLine(g.GetType()) prints "Circle" // Should run some spec

我可以访问一个类结构,但我不能修改它,如下所示:

Graphics
  Circle
  Line
  etc.
再说一遍,我不能修改它!这些都有单独的属性,如
半径
第一点
最后点
,以及一些常见属性

我想创建一个接受
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(Graphics g) { ... }
ToJson(Circle g) { ... }
ToJson(Line g) { ... }
起初我想象我可以巧妙地重载
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(Graphics g) { ... }
ToJson(Circle g) { ... }
ToJson(Line g) { ... }
然而,这当然适用于每次重载的通用
ToJson(图形)

我相信我可以做到以下几点:

if (g is Circle) ...
if (g is Line) ...
if (g is Graphics) ...
或者创建一个字典来降低每种类型的复杂性,但这并不是最好的方法


我所考虑的

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

我已经研究了双重分派和访问者模式,但我不确定它们是否满足我的要求,因为它们看起来像是我必须修改这些类(或者可能我只是没有完全理解它们),并且(然而,有点明显)泛型也基本上是不存在的,因为它们要求我提前知道这是什么类型的
图形
对象


那么有两个问题:

如果(g是Type)
,除了使用字典或其他
方法之外,还有更好的方法吗


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

不需要修改基类,也不需要在具体类型变成通用的
图形之前访问它,不幸的是,我认为除了检查
Graphics
对象的运行时类型之外,您什么都做不了

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

switch (g)
{
    case Circle circle: ... break;
    case Line line: ... break;
    default: /* Oh no! */ break;
}
就我个人而言,我不认为使用字典比使用这样的switch语句有什么好处——两者都可以放在一个独立的方法中(这样可以减少违反打开/关闭原则的次数),但这种转换会便宜得多

您还可以使用
动态
,这会导致运行时执行后期绑定:

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

。。。尽管动态有相当大的运行时开销,通常被认为是有味道的。

如果可以修改类型,可以添加一个虚拟/抽象ToJson实例方法,并根据需要进行重写。在“规则引擎”中使用反射来找到ToJson代码的正确实现可能是最好的方法。因此,是的,实现这一点的委托/对象类型的字典可能是我自己选择的。装饰器模式?正如您所指出的,要使用访问者模式进行双重分派,您需要“已访问”类来实现一个方法,该方法在适当的方法上调用“visitor”类。我在这里给出一个简单的例子:当您有一组相关对象时,您通常使用访问者模式,您需要对这些对象执行各种分析或转换过程,每个操作的具体细节取决于访问对象和访问者对象的运行时类型。谢谢您的输入Eric-我会仔细阅读!
开关
正在使用某种模式匹配?我不知道C中的switch语句可以做到这一点:)@尼克:是的,自从C#7.0以来,天哪,已经有一段时间了。我上一次使用C#是在5.0时,公平地说,我觉得自己老了,自5.0以来没有发生过任何突破性的事情(除了Roslyn)——它有很多小的改进。不过,C#8将再次成为开创性的项目