views:

102

answers:

2

C# - .net 3.5

I have a family of classes that inherit from the same base class. I want a method in the base class to be invoked any time a property in a derrived class is accessed (get or set). However, I don't want to write code in each and every property to call the base class... instead, I am hoping there is a declarative way to "sink" this activity into the base class.

Adding some spice to the requirement, I do need to determine the name of the property that was accessed, the property value and its type.

I imagine the solution would be a clever combination of a delegate, generics, and reflection. I can envision creating some type of array of delegate assignments at runtime, but iterating over the MemberInfo in the constructor would impact performance more than I'd like. Again, I'm hoping there is a more direct "declarative" way to do this.

Any ideas are most appreciated!

+2  A: 

I don't believe this is possible to do declaratively, i have never seen it done that way. What you can do though is implement the INotifyPropertyChanged interface on your base class, and have the implementation of the interface in the base class. Something like this:

public class A : INotifyPropertyChanged
{

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    protected virtual void RaiseOnPropertyChanged(object sender, string propertyName)
    {
        if (this.PropertyChanged != null)
            PropertyChanged(sender, new PropertyChangedEventArgs(propertyName);
    }

    public A()
    {
        this.PropertyChanged += new PropertyChangedEventHandler(A_PropertyChanged);
    }

    void A_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //centralised code here that deals with the changed property
    }
}


public class B : A
{
    public string MyProperty
    {
        get { return _myProperty; }
        set 
        {
            _myProperty = value;
            RaiseOnPropertyChanged(this, "MyProperty");
        }
    }

    public string _myProperty = null;
}
slugster
I should also point out that while INotifyPropertyChanged allows you to pass a property name, it doesn't take a rocket scientist to take the concept one step further and write your own version of the interface that also allows property value etc to be passed. Although what you are proposing, while it may sound clever in theory, is going to add a LOT of overhead to your application, and you will have to consider having conditional compilation switches in your code.
slugster
+3  A: 

You can't do it automatically, but you can pretty much get 95% for free. This is a classic case for aspect-oriented programming. Check out PostSharp, which has the OnFieldAccessAspect class. Here's how you might solve your problem:

[Serializable]
public class FieldLogger : OnFieldAccessAspect {
    public override void OnGetValue(FieldAccessEventArgs eventArgs) {
        Console.WriteLine(eventArgs.InstanceTag);
        Console.WriteLine("got value!");
        base.OnGetValue(eventArgs);
    }

    public override void OnSetValue(FieldAccessEventArgs eventArgs) {
        int i = (int?)eventArgs.InstanceTag ?? 0;
        eventArgs.InstanceTag = i + 1;
        Console.WriteLine("value set!");
        base.OnSetValue(eventArgs);
    }

    public override InstanceTagRequest GetInstanceTagRequest() {
        return new InstanceTagRequest("logger", new Guid("4f8a4963-82bf-4d32-8775-42cc3cd119bd"), false);
    }
}

Now, anything that inherits from FieldLogger will get the same behavior. Presto!

John Feminella