2017-04-07 32 views
0

我有一个不同的Line类的继承树,从抽象Line-classes开始。我希望能够将每一行与每一行相交,有时候,我也不知道任何运行时类型,例如,我打电话Line.Intersect(Line)(所以我需要双重调度)。这将总是调用被覆盖的最为抽象的过载 - 方法,例如, Circle.Intersect(Line)而不是Circle.Intersect(actualType)。下面是一些示例代码:单个继承树内的双派遣

class Program 
{ 
    static void Main(string[] args) 
    { 
    Line straightLine = new StraightLine(); 
    Line circle = new Circle(); 

    // Will print: "Circle intersecting a line." 
    // But should print: "Circle intersecting a straight line." 
    circle.Intersect(straightLine); 

    Console.ReadLine(); 
    } 
} 


abstract class Line 
{ 
    public abstract void Intersect(Line line); 

    public abstract void Intersect(StraightLine straightLine); 

    public abstract void Intersect(Circle circle); 
} 


class StraightLine : Line 
{ 
    public override void Intersect(Line line) 
    { 
    Console.WriteLine("Straigth line intersecting a line."); 
    } 

    public override void Intersect(StraightLine straightLine) 
    { 
    Console.WriteLine("Straight line intersecting a straight line."); 
    } 

    public override void Intersect(Circle circle) 
    { 
    Console.WriteLine("Straight line intersecting a circle."); 
    } 
} 


class Circle : Line 
{ 
    public override void Intersect(Line line) 
    { 
    Console.WriteLine("Circle intersecting a line."); 
    } 

    public override void Intersect(Circle circle) 
    { 
    Console.WriteLine("Circle intersecting a circle."); 
    } 

    public override void Intersect(StraightLine straightLine) 
    { 
    Console.WriteLine("Circle intersecting a straight line."); 
    } 
} 

一个可能的解决方法是使用dynamic,这是我目前做的。但是,我想迁移到.NET标准库,其中dynamic不允许。

还有其他方法可以使这项工作?如果有帮助,我愿意将抽象类切换为一个或多个接口。也许访问者模式是适用的,虽然我只看到它用于不同的继承树(并发现它很难看)。

回答

0

可以使用反射模拟双派遣。针对.NET标准1.1和使用Nuget包System.ReflectionIntersect(Line line)-方法不需要是抽象或虚拟的,但只需要执行一次。

这是.NET标准库整个示例代码(我现在返回string而不是使用Console.WriteLine(),因为后者无法在.NET标准):

using System.Reflection; 

namespace IntersectLibrary 
{ 
    public abstract class Line 
    { 
    public string Intersect(Line line) 
    { 
     var method = this.GetType().GetRuntimeMethod(nameof(Intersect), new[] { line.GetType() }); 
     return (string)method.Invoke(this, new[] { line }); 
    } 

    public abstract string Intersect(StraightLine straightLine); 

    public abstract string Intersect(Circle circle); 
    } 


    public class StraightLine : Circle 
    { 
    public override string Intersect(StraightLine straightLine) 
    { 
     return "Straight line intersecting a straight line."; 
    } 

    public override string Intersect(Circle circle) 
    { 
     return "Straight line intersecting a circle."; 
    } 
    } 


    public class Circle : Line 
    { 
    public override string Intersect(Circle circle) 
    { 
     return "Circle intersecting a circle."; 
    } 

    public override string Intersect(StraightLine straightLine) 
    { 
     return "Circle intersecting a straight line."; 
    } 
    } 
} 

请注意,当针对.NET Framework,System.Reflection提供了不同的方法,并且需要修改代码。

在一个控制台应用程序,会发生以下情况:

using System; 
using IntersectLibrary; 

namespace ConsoleApplication 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     Line straightLine = new StraightLine(); 
     Line circle = new Circle(); 
     Circle circle2 = new Circle(); 

     // Calls "Line.Intersect(Line)", and correctly 
     // prints "Circle intersecting a straight line.". 
     Console.WriteLine(circle.Intersect(straightLine)); 

     // Also calls "Line.Intersect(Line)", 
     // since the argument's compile-time type is "Line". 
     Console.WriteLine(circle2.Intersect(straightLine)); 

     // Calls "Line.Intersect(Circle)", 
     // since the argument's compile-time type is "Circle". 
     // At runtime, the call will be resolved to 
     // "StraightLine.Intersect(Circle)" via single dispatch. 
     Console.WriteLine(straightLine.Intersect(circle2)); 

     Console.ReadLine(); 
    } 
    } 
} 

如果你现在有编译时类型Line和具体类型之一的一个对象(例如Circle),最好打电话Line.Intersect(Circle),因为这不需要(较慢)反射来解决方法调用。然而,Circle.Intersect(Line)也将工作,最重要的是,现在总是可以调用Line.Intersect(Line)