2010-12-14 10 views
21

В question о пользе IoC контейнер, победившая податель отметил, что с контейнером IoC вы можете принять это:Круговой код. IoC на помощь

public class UglyCustomer : INotifyPropertyChanged 
{ 
    private string _firstName; 
    public string FirstName 
    { 
     get { return _firstName; } 
     set 
     { 
      string oldValue = _firstName; 
      _firstName = value; 
      if(oldValue != value) 
       OnPropertyChanged("FirstName"); 
     } 
    } 

    private string _lastName; 
    public string LastName 
    { 
     get { return _lastName; } 
     set 
     { 
      string oldValue = value; 
      _lastName = value; 
      if(oldValue != value) 
       OnPropertyChanged("LastName"); 
     } 
    } 
} 

к этому:

var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper()); 

Вопросы:

  • Какой волшебный контейнер IoC обеспечивает это доброту?
  • Пример реализации этого?
  • Любые недостатки?
  • В проекте со сложными зависимостями, буду ли я плакать, когда пытаюсь применить привязку данных к этим объектам?
+1

Я уверен, что ответ просто дразнит вас «идеей», а не реальной реализацией. –

+1

@chibacity. В этом случае Бен Шейрман лучше дразнит, чем любой проститутка, которого я когда-либо видел. (В кино, конечно). – AngryHacker

+0

, если вам нужен Клиент без каких-либо логических, но чистых уведомлений об изменении DTO и изменения свойств, было бы лучше объявить его как интерфейс, ICustomer, и это не так уж важно для создания конкретного класса с генерацией динамического кода. –

ответ

9

Для вашего второго фрагмента кода для работы, NotifyPropertyChangedWrapper бы, конечно, использовать отражение (или dynamic), чтобы создать класс, который предоставляет интерфейс, совместимый с Customer и реализует автоматическое уведомление свойств. Не должно быть никаких проблем с привязкой данных, но будет немного накладных расходов.

упрощена реализация, которая использует динамический объект может выглядеть примерно так:

public class NotifyPropertyChangedWrapper<T> 
    : DynamicObject, INotifyPropertyChanged 
{ 
    private T _obj; 

    public NotifyPropertyChangedWrapper(T obj) 
    { 
     _obj = obj; 
    } 

    public override bool TryGetMember(
     GetMemberBinder binder, out object result) 
    { 
     result = typeof(T).GetProperty(binder.Name).GetValue(_obj); 
     return true; 
    } 

    // If you try to set a value of a property that is 
    // not defined in the class, this method is called. 
    public override bool TrySetMember(
     SetMemberBinder binder, object value) 
    { 
     typeof(T).GetProperty(binder.Name).SetValue(_obj, value); 
     OnPropertyChanged(binder.Name); 
     return true; 
    } 

    // Implement OnPropertyChanged... 
} 

Очевидно, что любой код, который потребляет один из этих объектов будет терять статическую безопасность типов. Другой вариант - создать класс, реализующий тот же интерфейс, что и обернутый класс. В Интернете есть много примеров. Главное требование состоит в том, чтобы ваш Customer должен был либо быть interface, либо потребовать, чтобы все его свойства были виртуальными.

+0

Да, если вам нужен Клиент без логических, но чистых уведомлений об изменении DTO и ротации, было бы лучше объявить его как интерфейс, ICustomer, а затем такая конструкция не такая большая, чтобы создать конкретный класс с генерация динамического кода. –

+0

В любом случае, чтобы сделать это без DynamicObject? Я на .NET 3.5. И не отказываться от Intellisense. – AngryHacker

+0

Вам нужно было сделать то, что сказал Паули. Я делал это раньше, но код длинный, и у меня его нет. Вот статья, в которой кто-то еще делает это: http://grahammurray.wordpress.com/2010/04/13/dynamically-generating-types-to-implement-inotifypropertychanged/ – Jacob

2

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

3

Чтобы сделать это в общем виде (то есть один фрагмент кода, реализующий INotifyPropertyChanged для любого класса), используйте прокси-сервер. Для этого существует множество реализаций: Castle.DynamicProxy или LinFu или Unity. Эти прокси-библиотеки имеют хорошую поддержку в контейнерах IoC, например DynamicProxy имеет хорошую интеграцию с перехватом Castle Windsor и Unity (или тем, что он называется) имеет, очевидно, хорошую интеграцию с контейнером Unity.

1

Если вы ищете специальное решение для создания объектов с возможностью создания объектов, вы должны посмотреть PropertyChanged.Fody (ранее NotifyPropertyWeaver). Это перезаписывает классы, реализующие INotifyPropertyChanged, чтобы включить код уведомления. На странице github есть пример.

По-моему, это более аккуратно, чем использование предлагаемого контейнерного решения IOC. Тем не менее, это библиотека, специфичная для привязки INotifyPropertyChanged, поэтому не применима в качестве общего решения, как обсуждалось в вашем связанном вопросе.

+0

Вопрос был конкретно задан вопрос о том, какой *** контейнер IOC *** предоставил эту функцию. Не открывайте двухлетний вопрос ***, который имеет принятый ответ ** с ответом, который на самом деле не затрагивает вопрос. – jgauffin

+0

Я интерпретировал этот вопрос как относящийся к сокращению кода, я отвечал с этой точки зрения. Я считаю, что основное внимание МОК в основном связано с тем, что он был вдохновлен другим вопросом МОК. Даже если мой ответ не использует IOC, я считаю, что полезно отметить, что другие методы могут лучше подойти для достижения желаемого результата. Кроме того, [этот вопрос по мета] (http://meta.stackexchange.com/questions/20524/reviving-old-questions) приходит к выводу, что ответы на старые вопросы в порядке. –