22

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?
Community
  • 1
  • 1
AngryHacker
  • 59,598
  • 102
  • 325
  • 594
  • 2
    I am pretty sure that the answer is just teasing you with an "idea" rather than an actual implementation. – Tim Lloyd Dec 14 '10 at 02:16
  • 1
    @chibacity. In that case, Ben Scheirman is a better tease than any hooker I've ever seen. (In a movie, of course). – AngryHacker Dec 14 '10 at 02:21
  • if you needed a Customer with no logic but pure DTO and property change notifications it would be better to declare it as a interface, ICustomer, and it isn't that big of a deal to create a concrete class with dynamic code generation. – Pauli Østerø Dec 14 '10 at 02:34

4 Answers4

9

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.

Jacob
  • 77,566
  • 24
  • 149
  • 228
  • yes, if you needed a Customer with no logic but pure DTO and roperty change notifications it would be better to declare it as a interface, ICustomer, and then such a construct isn't that big of a deal to create a concrete class with dynamic code generation. – Pauli Østerø Dec 14 '10 at 02:33
  • Anyway to do this without the DynamicObject? I am on .NET 3.5. And not giving up Intellisense. – AngryHacker Dec 14 '10 at 02:36
  • You'd have to do what Pauli said. I've done this before, but the code is long, and I don't have it available. Here's an article where someone else does this: http://grahammurray.wordpress.com/2010/04/13/dynamically-generating-types-to-implement-inotifypropertychanged/ – Jacob Dec 14 '10 at 02:40
  • @AngryHacker Mauricio's answer below with DynamicProxy is a pretty good alternative. DynamicProxy itself is an alternative to using .Net proxies (TransparentProxy + RealProxy) and MarshalByRefObject, which would be yet another alternative. – Tim Lovell-Smith Nov 20 '12 at 21:27
3

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.

David Turvey
  • 2,891
  • 6
  • 27
  • 29
  • The question was specifically asking about which ***IOC container*** that provided that feature. Don't open up a two year old question ***that has an accepted answer** with an answer which doesn't really address the question. – jgauffin Jul 02 '13 at 10:14
  • 2
    I interpreted this question to be related reducing code cruft, I was answering from that perspective. I think the IOC focus is mainly because it was inspired by another IOC question. Even if my answer does not use IOC I think it is valuable to point out that other techniques may be better suited to achieving the desired result. Also, [this question on meta](http://meta.stackexchange.com/questions/20524/reviving-old-questions) concludes that answering old questions is ok. – David Turvey Jul 02 '13 at 13:03
3

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.

Mauricio Scheffer
  • 98,863
  • 23
  • 192
  • 275
2

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

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Jerod Venema
  • 44,124
  • 5
  • 66
  • 109