据我所知,这里需要multiple dispatch,也就是说,如果每种类型有两个方法,则动态决定调用哪个方法.
TL;DR访问者模式、动态关键字或switch 盒.在任何情况下,您都需要 for each 子类型单独编写函数块(在此块或函数中,您将拥有具体子类型,因此可以访问其所有成员).
在实践中,我会说切换 case 的方式是使用最多的,动态的我认为几乎从来没有.
访客
其中一个解决方案是在这里使用访客 pattern.您需要为您使用的每个子类型使用一个单独的方法,然后可以像这样使用它.
public abstract class Node
{
public Node parent;
public abstract void Accept(访客 visitor);
}
public class InnerNode : Node
{
internal Node leftChild, rightChild;
internal int someInnerNodeMember;
public override void Accept(访客 visitor)
{
visitor.Visit(this);
}
}
public class OuterNode : Node
{
internal float someOuterNodeMember;
public override void Accept(访客 visitor)
{
visitor.Visit(this);
}
}
public class 访客
{
public void Visit(InnerNode inner)
{
Console.WriteLine($"Inner node {inner.someInnerNodeMember}" );
}
public void Visit(OuterNode outer)
{
Console.WriteLine($"Outer node {outer.someOuterNodeMember}");
}
}
public class Program
{
public static void Main()
{
var visitor = new 访客();
var inner = new InnerNode
{
leftChild = new InnerNode { someInnerNodeMember = 1 },
rightChild = new OuterNode { someOuterNodeMember = 12 }
};
inner.leftChild.Accept(visitor);
inner.rightChild.Accept(visitor);
}
}
访问者基本上是您应用逻辑的地方,所以如果您希望InnerNode是能够区分内部和外部 node 类型的地方,那么它也是访问者,您可以将访问器方法移动到内部 node 并重写程序,如下所示
public abstract class Node
{
public Node parent;
public abstract void Accept(I访客 visitor);
}
public class InnerNode : Node, I访客
{
internal Node leftChild, rightChild;
internal int someInnerNodeMember;
public void PrintChildrenDetails()
{
leftChild?.Accept(this);
rightChild?.Accept(this);
}
public override void Accept(I访客 visitor)
{
visitor.Visit(this);
}
public void Visit(InnerNode inner)
{
Console.WriteLine($"Inner node {inner.someInnerNodeMember}");
}
public void Visit(OuterNode outer)
{
Console.WriteLine($"Outer node {outer.someOuterNodeMember}");
}
}
public class OuterNode : Node
{
internal float someOuterNodeMember;
public override void Accept(I访客 visitor)
{
visitor.Visit(this);
}
}
public interface I访客
{
void Visit(InnerNode inner);
void Visit(OuterNode inner);
}
public class Program
{
public static void Main()
{
var inner = new InnerNode
{
leftChild = new InnerNode { someInnerNodeMember = 1 },
rightChild = new OuterNode { someOuterNodeMember = 12 }
};
inner.PrintChildrenDetails();
}
}
动态
使用动态关键字也可以获得相同的结果,但不推荐使用(它有性能问题e.g. see here)
public abstract class Node
{
public Node parent;
}
public class InnerNode : Node
{
internal Node leftChild, rightChild;
internal int someInnerNodeMember;
public void PrintChildrenDetails()
{
Process((动态)leftChild);
Process((动态)rightChild);
}
public void Process(InnerNode inner)
{
Console.WriteLine($"Inner node {inner.someInnerNodeMember}");
}
public void Process(OuterNode outer)
{
Console.WriteLine($"Outer node {outer.someOuterNodeMember}");
}
}
public class OuterNode : Node
{
internal float someOuterNodeMember;
}
public class Program
{
public static void Main()
{
var inner = new InnerNode
{
leftChild = new InnerNode { someInnerNodeMember = 1 },
rightChild = new OuterNode { someOuterNodeMember = 12 }
};
inner.PrintChildrenDetails();
}
}
切换表达式
只需使用Switch表达式并处理每种类型用例.
public abstract class Node
{
public Node parent;
}
public class InnerNode : Node
{
internal Node leftChild, rightChild;
internal int someInnerNodeMember;
public void PrintChildrenDetails()
{
Process(leftChild);
Process(rightChild);
}
public void Process(Node node)
{
switch (node)
{
case InnerNode inner:
Console.WriteLine($"Inner node {inner.someInnerNodeMember}");
break;
case OuterNode outer:
Console.WriteLine($"Outer node {outer.someOuterNodeMember}");
break;
}
}
}
public class OuterNode : Node
{
internal float someOuterNodeMember;
}
public class Program
{
public static void Main()
{
var inner = new InnerNode
{
leftChild = new InnerNode { someInnerNodeMember = 1 },
rightChild = new OuterNode { someOuterNodeMember = 12 }
};
inner.PrintChildrenDetails();
}
}