Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cruft code. IoC to the rescue

Tags:

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?
like image 780
AngryHacker Avatar asked Dec 14 '10 02:12

AngryHacker


2 Answers

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.

like image 73
Jacob Avatar answered Nov 06 '22 01:11

Jacob


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.

like image 45
Mauricio Scheffer Avatar answered Nov 06 '22 01:11

Mauricio Scheffer