Archive

I had a new interesting discussion, this time with John Vanspronssen. I'm not sure I've understood all he has in mind, but I was challenged by the idea of 'composed aspects', that is, aspects composed of many transformations. In order to avoid confusion with object composition, I chose to rename this combined aspects. I first planned to implement this in a later phase, but this discussion just excited me to do it... and it's done! So what's a composed aspect? As I said, it is an aspect composed of many sub-aspects. John gave the binding aspect as an example. This aspect 'simply' raises an event OnPropertyChanged. Say I have the following base code:
interface IBindable
{
event EventHandler OnPropertyChanged;
}

[Bindable]
class MyClass
{
private int field1;

public int Field1
{
 get { return field1; }
 set { field1 = value; }
}
}
The post-compiled code should look like this:
class MyClass : IBindable
{
private int field1;

public event EventHandler OnPropertyChanged;

public int Field1
{
  get { return field1; }
  set
  {
      field1 = value;
      if (this.OnPropertyChanged != null)
      {
          this.OnPropertyChanged(this, EventArgs.Empty);
      }
  }
}
}
There are two sub-aspects combined in the Binding aspect:
  1. A CompositionAspect: adding the IBinding interface and its implementation.
  2. An OnMethodBoundaryAspect applied to the method set_MyProperty method: raising the OnPropertyChanged method. If there were more than one property, there would be one aspect of this type for each writable property.
The aspect implementation has less than 100 lines of code including blank ones. I don't copy it in this post, but you can see it online. The following points are interesting:
  1. The class BindableImplementation is the implementation of the IBindable interface. This type is composed inside the target the AddBindableInterfaceAspect aspect, which is derived from CompositionAspect.
  2. The aspect OnPropertySetAspect is derived from OnMethodBoundaryAspect and implements only the OnExit method. The only thing it does is to retrieve the implementation of IBindable for this instance (that is, the composed BindableImplementation object) and raise the OnObjectChanged event.
  3. The class BindableAttribute is the principal class and the only public one. It is derived from CombinedAspect and implement the method ProvideAspects. This method is the most interesting. First it adds the AddBindableInterfaceAspect to the type, then it scans all the writable properties in this type and applies the OnPropertySetAspect to them. This method is of course executed at compile time.
A good question is: how can the OnProperySetAspect retrieve the implementation of the IBindable interface? It took me at least two nights to answer. Let me ask the question more formally: suppose that an object is composed of different behaviours (composed objects and aspects). How can these different behaviour exchange information between themselves? I think that this problem should ideally be solved by the platform, that is, by .NET itself. The platform should ideally have a concept that 'an instance is the friend of another'. If the developer chooses to apply an aspect to a class, it is legitimate to give this aspect more permissions on the target type than the permissions we want to give to everybody ('public' access). And it is not possible for the aspect to have access only to protected data, since the aspect is not derived from the target type. The solution I designed is to rely on credentials. Each instance (at least each instance of a type that wants to 'share' something) has its own 'secret' called credentials. The can give the credentials to some other instance. Then, this instance can use these credentials to get access to some 'protected' data (but here protected by these credentials, not by restriction of visibility). This mechanism is currently only used to retrieve the instance implementing an interface that has been composed by CompositionAspect. Composed types may optionally implement the interface IComposed , where T is the composed interface (IBindable in our example). This interface has a single method GetImplementation... that requires the credentials. How can the OnPropertySetAspect know the credentials? These are passed through the event arguments (MethodExecutionEventArgs). That is, aspects will receive the credentials to access 'protected' data of the aspected instance. But only of this instance! I've said this was designed, but this is not completely implemented. In the version I put online tonight, credentials are not yet checks. And there are still problems if you try to apply the same custom attributes on a class and its parent class. This will be solved during the next week or two. Enjoy! Gael

Comments (3) -

Bob31334
Bob31334
11/6/2009 5:52:23 PM #

Hi Gael,

PostSharp is amazing!  I was trying to do binding with another framework, only to find that you already have a working example of it to go along with PostSharp.  

One thing doesn't work, however, which is sending one of the NotifyPropertyChanged-attributed objects across the wire using WCF.  After much digging via Reflector, I figured out two things:
a) PostSharp 'credentials' generation code is weaved into the object's default constructor; AND
b) WCF does not call any constructors when deserializing objects!  It emits special IL instructions, it would seem, to get around the usual call to a constructor.

So... Is there another way to call PostSharp's code which generates these credentials, using perhaps the [OnDeserializing] callback?  If not, I think I can get around the problem by avoiding composition altogether and just making my object implement INotifyPropertyChanged.  But it would be great to get PostSharp working for this.

Thanks!
Bob

Gael Fraiteur
Gael Fraiteur
11/7/2009 4:09:26 PM #

Support for WCF is described here:
doc.postsharp.org/.../InstanceInitialization.html

Bob31334
Bob31334
11/9/2009 5:10:43 PM #

Hmm... I can't get that link to work.

However, I did find this:
www.postsharp.org/.../announcing-postsharp-1.5-rc1

Is 'awareness' what you were referring to?

Thanks,
Bob

Comments are closed