2013-11-01 1 views
2

У меня есть небольшая проблема в моем коде здесь, я думаю, интересно:Как потупив перегруженный метод

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

Я пытаюсь вызвать методы PreVisit и PostVisit на узле объекта ISceneNode, который родительский класс для других типов узлов. Однако, поскольку это «слишком общее» из объектных отношений, я не имею право называть методы:

//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? Это потому, что он не знает, какой метод выбрать? Как я могу объяснить это в своем коде и обходным путем?

+1

Это называется многократной (или динамической) отправкой. Вам нужен шаблон посетителя. – SLaks

+0

У меня есть шаблон посетителя. – Musicode

+0

Ум объясняет далее? Это фактически реализация класса SearchVisitor, который выполняет поиск по дереву этих узлов. – Musicode

ответ

2

Когда вы вызываете свой метод, объект 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); 
} 
1

dynamic C# делает это красиво:

PreVisit((dynamic)node); 

что выбрать подходящий метод во время выполнения с помощью C# семантику.

+0

Но поскольку реализации все равно, что лучше сделать, используя наследование, я думаю. Просто объявите метод под названием PreVisit (ISceneNode). При необходимости сам метод может вызвать виртуальные перегрузки. – PMF

+0

@PMF самому классу узла должен быть виртуальный метод для использования виртуальной диспетчеризации. Это будет работать, да. Но это означает, что все подклассы должны придерживаться этого протокола и знать, что такое посетитель. Я бы предпочел, чтобы класс узлов не знал концепцию посещающих узлов. – usr

+0

Хорошо, тогда вы могли бы, конечно, написать свои методы посетителя, используя шаблонные аргументы или используя методы расширения. – PMF