Cruft code. IoC to the rescue

无人久伴 提交于 2019-12-03 03:45:31

问题


In question about usefulness of IoC Container, the winning submitter mentioned that with an IoC container you can take this:

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");
        }
    }
}

to this:

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

Questions:

  • Which magic IoC container provides this goodness?
  • An example implementing this?
  • Any downsides?
  • In a project with complex dependencies, will I be crying when I try to apply data binding to these objects?

回答1:


For your second code snippet to work, NotifyPropertyChangedWrapper would certainly have to use reflection (or dynamic) to generate a class that provides an interface compatible with Customer and implements the automatic property notification. There shouldn't be any data binding issues, but there would be a little overhead.

An simplified implementation that uses a dynamic object could look something like this:

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...
}

Obviously, any code that consumes one of these objects would lose any static type safety. The other option is to generate a class implementing the same interface as the class being wrapped. There are lots of examples for this on the web. The main requirement is that your Customer would have to either be an interface or it would need all of its properties to be virtual.




回答2:


To do this in a generic way (i.e. a single piece of code implementing INotifyPropertyChanged for any class) use a proxy. There are lots of implementations around to do this with Castle.DynamicProxy or LinFu or Unity. These proxy libraries have good support in IoC containers, for example DynamicProxy has good integration with Castle Windsor and Unity interception (or whatever it's called) has obviously good integration with the Unity container.




回答3:


I've never used it, but you can supposedly create something like this using PostSharp.




回答4:


If you are looking for a specific solution for auto-generating bindable objects you should look at PropertyChanged.Fody (previously NotifyPropertyWeaver). This rewrites classes implementing INotifyPropertyChanged to include the notification code. There is an example on the github page.

In my opinion this is neater than using the proposed IOC container solution. However, it is a library specific to INotifyPropertyChanged binding so is not applicable as a general solution, as was being discussed in your linked question.



来源:https://stackoverflow.com/questions/4435271/cruft-code-ioc-to-the-rescue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!