Код Крафта.IoC на помощь - PullRequest
       4

Код Крафта.IoC на помощь

21 голосов
/ 14 декабря 2010

В вопросе о полезности Контейнера 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-контейнер обеспечивает это качество?
  • Пример реализации этого?
  • Есть ли минусы?
  • В проекте со сложными зависимостями я буду плакать, когда пытаюсь применить привязку данных к этим объектам?

Ответы [ 4 ]

9 голосов
/ 14 декабря 2010

Чтобы ваш второй фрагмент кода работал, 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, либо все его свойства должны быть виртуальными.

3 голосов
/ 14 декабря 2010

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

2 голосов
/ 14 декабря 2010

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

1 голос
/ 02 июля 2013

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

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

...