Reputation: 1308
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
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