Полиморфизм и перегрузка статическими методами в C #. - PullRequest
7 голосов
/ 28 июля 2011

Я пытался сгенерировать Фабрику, которая должна возвращать другой объект общего интерфейса (скажем, Item) в соответствии с входным параметром (я называю это контекстом) функции getItem(A context)

Теперь предположим, что я определил новый тип контекста: B, который наследуется от A.

Я хотел вернуть другой элемент в зависимости от того, был ли объект, переданный фабрике, класса Bили A.

Я попытался сделать следующее (перегружая метод):

class Factory
{
   static Item getItem(A context) {...}
   static Item getItem(B context) {...}
}

Это прекрасно работает, если я сделаю что-то вроде этого:

B bContext=new B();
Item it=Factory.getItem(bContext);

Однако, если я приведу объект к типу A:

A bContext=(A) new B();
Item it=Factory.getItem(bContext);

, будет вызван первый фабричный метод.

Я думал, что полиморфизм обеспечит выполнение второго метода даже послеприведение, и я хотел бы знать, если я что-то пропустил?

Я знаю, что я мог бы продолжать иметь один метод и использовать оператор is, чтобы проверить, какой тип переменной, но ядумал, что решение я представилвыше было немного элегантнее.

Ответы [ 2 ]

10 голосов
/ 28 июля 2011

Перегрузка решается в время компиляции (кроме использования динамической типизации в C # 4) на основе типа аргументов во время компиляции - и в вашем последнем фрагменте, тип времени компиляцииаргумент A, поэтому он вызывает Factory.getItem(A).

Только вызовы виртуальных методов являются полиморфными (с использованием overriding ), где фактический тип времени выполнения целевого объекта решает, какойРеализация звонить.Если для A и B имеет смысл иметь виртуальный метод (переопределяемый в B), который может быть вызван Factory.getItem для обработки различий, это здорово ... в противном случае вы застряли на любом из динамическихнабрав или что-то вроде is.

1 голос
/ 28 июля 2011

Вы не можете добиться того, что вы притворяетесь, так, как вы сейчас настраиваете вещи.

Один из вариантов - это иметь некоторую логику в ваших фабричных методах, которые могут различать тип аргумента.Неуклюжий, не симпатичный, но он работает:

class Factory
{
    static Item getItem(ContextA context)
    {
         if (context is ContextB) {...}
         else {...}
    }
}

Другой вариант - сделать объекты контекста ответственными за создание объекта.Например:

public class ContextA
{
     ....
     internal virtual Item CreateItem() { //specific creation logic for ContextA }
}

public class ContextB: ContextA
{
     ....
     internal override Item CreateItem() { //specific creation logic for ContextB }
}

А теперь вы можете сделать:

class Factory
{
    static Item getItem(ContextA context)
    {
         return context.CreateItem();
    }
}

Нет, если вы сделаете следующее: будет вызван

 ContextA context = new ContextB();
 Item item = Factory.getItem(context)

ContextB.CreateItem().

...