John Holliday
John Holliday

Reputation: 1308

How to use AOP (PostSharp) for Serialization?

Is it possible to inject code to read/write the properties of an object using a PostSharp aspect? For example, consider the following class:

[ BinarySerializable ] 
public class Employee { 
   public string Name {get; set; } 
   public string Title {get; set;} 
}

In this case, "BinarySerializable" would be a custom aspect that introduces a custom "IBinarySerializable" interface, as follows:

public interface IBinarySerializable 
{ 
   void Write(BinaryWriter writer); 
   void Read(BinaryReader reader); 
}

After compilation, the resulting class would look like this:

public class Employee : IBinarySerializable 
{ 
   public string Name {get; set;} 
   public string Title {get; set; }

   void IBinarySerializable.Write(BinaryWriter writer) 
   { 
      writer.Write(Name); 
      writer.Write(Title); 
   }

   void IBinarySerializable.Read(BinaryReader reader) 
   { 
      Name = reader.ReadString(); 
      Title = reader.ReadString(); 
   } 
}

Intuitively, I feel this should be possible using PostSharp, but I need some direction as to the right approach. If this is possible, then how to handle properties that are themselves injected by some other aspect?

UPDATE: I tried creating a simple example using the built-in PSerializable aspect, but ran into problems when members inherit from .NET framework classes that do not have that attribute.

Adding the [PSerializable] attribute to the EmployeeCollection class fails to compile with "Cannot apply [PSerializable] to type 'AOPSerialization.EmployeeCollection' because the base type does not have a [PSerializable] or [Serializer] attribute."

Omitting the [PSerializable] attribute from the EmployeeCollection class throws a runtime PortableSerializationException: Cannot find a serializer for type 'AOPSerialization.EmployeeCollection'.

For example:

[PSerializable]
public class AOPComponent
{
    public string Title { get; set; }
    public string Description { get; set; }
    public AOPComponent(string title, string description){...}
}

[PSerializable]
public class AOPComponentCollection<T> : ObservableCollection<T>
{...}

[PSerializable]
public class EmployeeCollection : AOPComponentCollection<Employee>
{...}

[PSerializable]
public class Company : AOPComponent
{
    public EmployeeCollection Engineers { get; set; }
    public EmployeeCollection Managers { get; set; }
}

I figured out that the Serializer and ImportSerializer attributes are used to tell the PortableFormatter which custom ISerializer or ISerializerFactory implementation to use.

But the question remains:

How to specify a custom serializer for the generic base collection type?

This approach fails because an attribute may not include type parameters.

[PSerializable, ImportSerializer(typeof(ObservableCollection<T>), typeof(AOPComponentSerializerFactory))]
public class AOPComponentCollection<T> : ObservableCollection<T> where T : AOPComponent
{...}

This approach fails because PostSharp cannot find a serializer for ObservableCollection< T >

[PSerializable, Serializer(typeof(AOPComponentSerializerFactory))]
public class AOPComponentCollection<T> : ObservableCollection<T> where T : AOPComponent
{...}

Upvotes: 0

Views: 710

Answers (1)

Gael Fraiteur
Gael Fraiteur

Reputation: 6857

It would be possible to do that with PostSharp, but only by using the low-level PostSharp SDK, which is undocumented and unsupported.

Good news are that we already implemented this for you, in the namespace PostSharp.Serialization. The aspect is [PSerializable] and the formatter is PortableFormatter.

Upvotes: 1

Related Questions