2011-12-20 2 views
4

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

case 1: return new A(arg1); // arg is int 

и т. Д., Для примерно 10 классов. Есть ли способ с генериками или делегатами сделать один метод, который будет принимать имя класса и создать экземпляр этого типа с аргументами?

Это помогло бы, поскольку, если я внес изменения в конструкторы, мне также придется изменить каждое экземпляр.

Делегат будет наиболее откровенным, но исследование говорит, что нет, чтобы назначать конструкторов делегатам.

ДОБАВЛЕНИЕ: Теперь я нахожусь на wifi с моим ноутбуком, а не только с моей ячейкой, поэтому здесь идет какой-то код.

Это пример того, что происходит сейчас:

switch (new Random().Next(4)) 
{ 
    case 3: 
     // classA : baseClass, args{int, bool, otherClass} 
     return new classA(arg1, arg2, arg3); 
    case 2: 
     // classB : baseClass, args{int, bool, otherClass} 
     return new classB(arg1, arg2, arg3); 
    case 1: 
     // classC : baseClass, args{int, bool, otherClass} 
     return new classC(arg1, arg2, arg3); 
    case 0: 
     // classD : baseClass, args{int, bool, otherClass} 
     return new classD(arg1, arg2, arg3); 
    default: 
     continue; 
} 

Я хотел бы назвать один cоздателем экземпляров в конце блока с тремя аргументами.

Решение Я думал это сделать и класс cоздателем экземпляров, который работает примерно так:

ClassInstantiator inst = new ClassInstantiator(arg1, arg2, arg3); 
switch(new Random().Next(4)) 
{ 
    case 4: 
     return inst.instantiate<classA>(); 
    ... 
} 

Это уже встроены в язык, или кто-нибудь знает более элегантное решение?

+0

+1 для отличного вопроса. –

+0

Понимаю, что Активатор - это техника, которую я частично описал выше. – kskid19

ответ

5

только конструктор, связанные с ограничением вы можете поставить на общий типе является new() ограничением, которое требует открытого конструктора без параметров.

Вы можете использовать отражение; пример предполагает, что все соответствующие типы имеют конструктор принимает Int, как в вашем примере, и что абстрактный базовый класс называется B:

public T CreateInstance<T>(int i) where T : B 
{ 
    return (T)Activator.CreateInstance(typeof(T), i); 
} 

Тогда вы назвали бы это так:

A a = CreateInstance<A>(3); 
+0

Побей меня, пей. +1. –

+1

Также обратите внимание, что если вы действительно используете ограничение 'new()', вы получаете генерируемый компилятором вызов 'Activator.CreateInstance' всякий раз, когда вы говорите' new'. –

5

Вы не можете уйти от того факта, что что-то должно на условной основе определять, что строить, но вы можете его инкапсулировать. Могу ли я представить вам один из самых популярных шаблонов GOF: http://en.wikipedia.org/wiki/Factory_method_pattern

например.

public abstract class MyBase(string name){} 
public class Concrete1 : MyBase{} 
public class Concrete2 : MyBase{} 

public class MyFactory 
{ 
    public MyBase Create(Criteria criteria) 
    { 
     //conditional logic/reflection 
    } 
} 
+0

Итак, у вас есть еще один класс для каждого класса, который вы хотите создать? ... проблема в том, что это не отвлекает меня от вызова с теми же аргументами для каждого оператора case. Например, я хотел бы сохранить имя класса A в переменной, а затем вызвать метод с использованием переменной, чтобы создать экземпляр требуемого класса с общими аргументами. – kskid19

+0

Нет, у вас есть один класс, который инкапсулирует выбор конкретного типа внутри одного метода, который возвращает базовый тип. Это требует, чтобы вы передавали что-то в качестве критерия для выбора. Вы упомянули тип, вы могли бы использовать это (в этом случае отражение может быть идеальным @phoog), или могут быть еще другие критерии для домена? –

0

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

Популярные IoC контейнеры:

+0

Я не согласен с вами, но вы можете объяснить дальше? В таком случае эти контейнеры могут создавать различные бетоны, зависящие от типа arg конструктора? –

+1

@MylesMcDonnell, как я понимаю вопрос, логика обусловлена ​​чем-то другим, кроме типа arg конструктора (я полагаю, что «все они имеют один и тот же конструктор» означает, что все конструкторы имеют одинаковое количество параметров с одним и тем же типом). – phoog

+0

Да, вы правы, мой комментарий выше был бессмыслицей в контексте этого вопроса. Хотя мне было бы интересно узнать, есть ли какие-либо контейнеры, которые могли бы выбрать конкретную имплантацию в соответствии с конкретным типом arg? Я ожидаю, что есть, и я ожидаю, что генерики являются фактором, обеспечивающим благоприятство. –

1

Вы можете создать словарь с именем класса как ключом и делегатом конструктора в качестве значения.

Dictionary<string,Func<int,BaseClass>> _dict = new Dictionary<string,Func<int,BaseClass>>(); 
_dict.Add("ClassA", i => new ClassA(i)); 
_dict.Add("ClassB", i => new ClassB(i)); 

// Create ClassA object by class name 
BaseClass obj = _dict["ClassA"](5); 
Смежные вопросы