2010-06-12 2 views
2

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

Я пытаюсь создать реализацию фабрики для моделирования заявление. Моделирование будет состоять из разных типов объектов, т. Е. Оно не является однородным симулятором в любом отношении. В результате будет множество очень разных конкретных реализаций, и только самые общие свойства будут абстрагированы на верхнем уровне.

Что бы я хотел сделать, это создать новые симуляционные объекты, вызвав метод на модели с серией именованных аргументов, представляющих параметры объекта, и чтобы модель выводила тип объекта описываемых входящими параметрами (из названий параметров и, возможно, их последовательностью) и вызова фабричного метода в соответствующем производном классе.

Например, если я передаю модели пару параметров (Param1 = 5000, Param2 = "Bacon"), я бы хотел, чтобы имена Param1 и Param2 принадлежали классу Blob1 и вызывали общая функция «getBlob1» с именованными параметрами Param1: = 5000, Param2: = «Bacon», тогда как если я пройду модель (Param1 = 5000, Param3 = 50), она вызовет аналогичный заводский метод для Blob2; потому что Param1 и Param3 в этом порядке «принадлежат» Blob2.

Я предвижу несколько вопросов, чтобы решить:

  • ли или нет, я могу подумать о доступных типов с именами параметров строки и как это сделать, если это возможно
  • ли или нет аккуратный способ делая соответствующий вывод конструктора из комбинаторных свойств списка аргументов, или я собираюсь сделать что-то, чтобы сделать это «вручную».
  • Если возможно, хотелось бы, чтобы класс модели мог принимать параметры как параметры, а не как некоторую коллекцию ключей и значений, что потребовало бы, чтобы модель отображала большое количество параметризованных методов во время выполнения без меня чтобы их явно указывать - предположительно один для каждого заводского метода, доступного в соответствующем пространстве имен.

Что я действительно спрашиваю, так это то, как вы собираетесь внедрять такую ​​систему, а не в том, действительно ли это возможно. У меня нет предусмотрительности или опыта работы с .NET-анализом, чтобы я мог самостоятельно разобраться. Надеюсь, это станет информативным обсуждением.

UPDATE:

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

Dim members() As Reflection.MethodInfo = Me.GetType.GetMethods() 
    Dim params_enum As IEnumerator(Of String) = params.Keys.GetEnumerator 

    While params_enum.MoveNext 
     members = Array.FindAll(members, _ 
           Function(m As Reflection.MethodInfo) Array.Exists(CType(m, Reflection.MethodInfo).GetParameters(), _ 
                        Function(mm As Reflection.ParameterInfo) mm.Name = params_enum.Current)) 
     If members.Count = 0 Then Return False 
    End While 
    Try 
     CType(members(0), Reflection.MethodInfo).Invoke(Me, params.Values.ToArray()) 
     Return True 
    Catch ex As Exception 
     Return False 
    End Try 

Это просто выбирает метод на текущем экземпляре и выполняет его. Я хотел бы распространить это на подмножество всех типов сборки. Я также хотел бы сделать это, если это возможно, путем предоставления этим типам решения, каковы их параметризованные требования к инициализации во время выполнения, исследуя их собственные свойства, то есть каждое свойство, помеченное параметром ParametrisedInitAttribute, соответствует точно одному именованному аргументу в методе фабрики. Это потребовало бы, чтобы у меня эти типы выставляли метод с N аргументами во время выполнения. Есть ли способ построить метод с произвольной сигнатурой и добавить его в реализацию класса во время выполнения или аналогичный способ делать такие вещи?

+0

Установлен ли полный набор возможных имен параметров? И имеет ли каждый конкретный параметр фиксированный тип? – tzaman

+0

tzaman: Хороший вопрос. Я полагаю, что ответ «зависит»; в том, что я еще не решил. Я имел в виду, чтобы позволить пользователю настраивать модель с помощью простой перетаскивания/копирования-вставки (например) данных Excel; и модель выводит те объекты, которые пользователь намеревался добавить посредством комбинации имеющихся значений. В идеале был бы случай, когда модель могла бы угадать, что означает каждое поле, когда заголовки опущены или что-то еще. В общем, однако, полный набор параметров будет известен модели во время выполнения, а не время разработки, но будет исправлено после этого. –

+0

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

ответ

1

Это кажется хорошим местом для использования новых функций dynamic .NET 4 - a DynamicObject может переопределить TryInvokeMember, чтобы изучить имя и аргументы, с которыми вызывается метод; вы можете использовать это для создания словаря фабричных методов, который будет называться динамически на основе переданных аргументов. Вот пример, который я только что приготовили:

Динамический класс фабрики:

class DynaTest : DynamicObject 
{ 
    Dictionary<string, Func<object[], object>> builders; 

    public DynaTest() 
    { 
     builders = new Dictionary<string, Func<object[], object>>(); 
     builders.Add("fur,fangs", args => 
        new Dog((string)args[0], (int)args[1])); 
     builders.Add("fur,claws", args => 
        new Cat((string)args[0], (string)args[1])); 
    } 

    public override bool TryInvokeMember(InvokeMemberBinder binder, 
             object[] args, out object result) 
    { 
     string key = String.Join(",", binder.CallInfo.ArgumentNames.ToArray()); 
     Func<object[], object> builder; 
     if (builders.TryGetValue(key, out builder)) 
     { 
      result = builder(args); 
      return true; 
     } 
     else 
     { 
      result = null; 
      return false; 
     } 
    } 
} 

Классы мы хотим построить:

class Dog 
{ 
    string _fur; 
    int _fangs; 
    public Dog(string fur, int fangs) 
    { 
     _fur = fur; 
     _fangs = fangs; 
    } 
    public void Bark() 
    { 
     Console.WriteLine("Woof! I have " + _fur + " fur and " 
          + _fangs + " fangs."); 
    } 
} 

class Cat 
{ 
    string _fur; 
    string _claws; 
    public Cat(string fur, string claws) 
    { 
     _fur = fur; 
     _claws = claws; 
    } 
    public void Meow() 
    { 
     Console.WriteLine("Meow! I have " + _fur + " fur and " 
          + _claws + " claws."); 
    } 
} 

Код испытания:

static void Main(string[] args) 
{ 
    dynamic dyn = new DynaTest(); 
    Dog d = dyn.Build(fur: "rough", fangs: 4); 
    d.Bark(); 
    Cat c = dyn.Build(fur: "shiny", claws: "sharp"); 
    c.Meow(); 
} 

Выход:

Woof! I have rough fur and 4 fangs. 
Meow! I have shiny fur and sharp claws. 

Примечание: это мой первый раз, играя с dynamic, поэтому могут возникнуть проблемы с этим, о которых я не знаю.

0

То, что вы хотите сделать, это вполне возможно с отражением и может быть сделано более или менее прямо вперед, как вы описали его:

  • перебрать все доступные типы. У вас есть разные варианты, как это сделать. Вы можете выбирать типы по общему подклассу, по определенному интерфейсу, пометить их атрибутом ... Это зависит от вашей конкретной реализации, что лучше для вас. Существуют также рамки, которые помогают сделать это, но снова вам нужно проверить свои конкретные требования.

  • Для всех этих типов вы можете получить «фабрику», которая может быть, например, конструктором.

  • Для всех этих заводов вы можете запросить требуемые параметры с их типами и именами.

  • Теперь вам необходимо определить некоторые правила упорядочения для этих заводов, и если вы хотите построить объект, вы просто просматриваете список и выполняете поиск по первой соответствующей фабрике.

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

Смежные вопросы