【问题标题】:How to Downcast to an Overloaded Method如何向下转换为重载方法
【发布时间】:2013-11-01 18:27:03
【问题描述】:

我的代码有一个小问题,我认为这很有趣:

foreach(ISceneNode node in (root as IGroupNode))
            {
                PreVisit(node);
                if (notFound == false)
                {
                    return node;
                }
                else
                    PostVisit(node);
            }

我试图在 ISceneNode 对象节点上调用方法 PreVisit 和 PostVisit,它是其他类型节点的父类。但是,因为这是对象关系的“太笼统”,所以我不允许调用方法:

//methods
void PreVisit(IDrawableNode drawable)
    {
        string targetName = drawable.Name;
        Boolean notFound = true;
        CompareToTarget(targetName, notFound, drawable);
    }

    void PreVisit(ITransformNode transform)
    {
        string targetName = transform.Name;
        Boolean notFound = true;
        CompareToTarget(targetName, notFound, transform);
    }

    void PreVisit(IStateNode state)
    {
        string targetName = state.Name;
        Boolean notFound = true;
        CompareToTarget(targetName, notFound, state);
    }

    void PreVisit(IGroupNode group)
    {
        string targetName = group.Name;
        Boolean notFound = true;
        CompareToTarget(targetName, notFound, group);
    }

IGroupNode、IStateNode 等都是从 ISceneNode 派生的……那为什么我不能只使用 ISceneNode 来调用这个重载方法呢?是因为它不知道选择哪种方法吗?如何在我的代码中解决这个问题并解决它?

【问题讨论】:

  • 这称为多(或动态)分派。你需要一个访问者模式。
  • 我确实有一个访客模式。
  • 介意进一步解释吗?这实际上是 SearchVisitor 类的实现,它在这些节点的树上执行搜索。
  • 如何将参数类型转换为所需类型? PreVisit(((IGroupNode)node));
  • 如果你将node设为动态类型变量,运行时会自动选择最匹配的重载,如果没有匹配则抛出异常:foreach (dynamic node in (group as IGroupNode))

标签: c# relationship downcast


【解决方案1】:

当你调用你的方法时,对象是ISceneNode,因为你没有定义PreVisit(ISceneNode),它会找不到合适的方法。

编译器将无法理解您已经为每个子类型定义了一个子案例。一种解决方案是对其进行强制转换以检查您的对象是否实现了其中一个子接口并在已转换对象上调用该方法。

当然,仅在其余代码中间编写它并不是一个很好的解决方案。正如 SLaks 提到的,您应该使用调度,例如 here,或使用 C# 4.0 关键字 dynamic,如图所示 here

这里是第二个链接的例子:

class Animal 
{ 
}

class Cat : Animal 
{ 
}

class Dog : Animal 
{ 
}

以下是专业:

void ReactSpecialization(Animal me, Animal other) 
{ 
    Console.WriteLine("{0} is not interested in {1}.", me, other); 
}

void ReactSpecialization(Cat me, Dog other) 
{ 
    Console.WriteLine("Cat runs away from dog."); 
}

void ReactSpecialization(Dog me, Cat other) 
{ 
    Console.WriteLine("Dog chases cat."); 
}

现在这是您在 C# 4.0 中使用 dynamic 定义双重调度的方式:

void React(Animal me, Animal other) 
{ 
    ReactSpecialization(me as dynamic, other as dynamic); 
}

然后运行

void Test() 
{ 
    Animal cat = new Cat(); 
    Animal dog = new Dog(); 

    React(cat, dog); 
    React(dog, cat); 
}

【讨论】:

    【解决方案2】:

    C# dynamic 做得很好:

    PreVisit((dynamic)node);
    

    使用 C# 语义在运行时选择适当的方法。

    【讨论】:

    • 但由于实现都是相同的,我认为最好使用继承来完成。只需声明一个名为PreVisit(ISceneNode) 的方法。如果需要,方法本身可以调用虚拟重载。
    • @PMF 节点类本身必须有一个虚拟方法才能从虚拟调度中受益。那会起作用的,是的。但这意味着所有子类都必须遵守该协议并知道访问者是什么。我宁愿节点类不知道访问节点的概念。
    • 好的,那么您当然可以使用模板化参数或扩展方法编写访问者方法。
    猜你喜欢
    • 1970-01-01
    • 2018-02-28
    • 2011-07-11
    • 1970-01-01
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 1970-01-01
    相关资源
    最近更新 更多