.NET Reflection can be quite handy to transform one object to another, and specially when the target data structure varies a lot. Lets say, a “source party” has a stable Source data structure. But different clients have different requirement and expects to served with data in different format. These clients may pass their object instances in their own format and expect to be served with data in their structure. Let me make up an Example here:
Source Data Structure which is consistent and never changes.
Client 1 wants data to be transformed/served in the following structure
Client 2 wants data to be transformed/served in the following structure
and there may be other N-number of clients with N-number of structures, on which “Source Party” has no control.
The use of .NET Attribute and .NET Reflection can produce a very powerful solution to address this kind of scenario. So instead of writing different transforms for different clients, “source party” can simply ask clients to mark their class properties with custom attributes that the “source party” can understand. When clients mark their classes with custom attributes the “source party” can easily take advantage of .NET Reflection to analyze those objects runtime and can act accordingly.
A .NET Attribute class can be designed to keep track of of the Mapping between the source and target data structure.
The client can mark their class/properties with this custom attribute for the (target -> source) mapping.
As the mapping has been performed, we can take advantage of .NET Reflection to transform/serve data in different structure ( infact any structure – considering mapping is done properly ). Lets look at the following magical piece of code.
public
class TransformHelper {
public
Source SourceObject {
get;
set;
}
public
object GetTransformedObjectObject(object obj) {
foreach (PropertyInfo property in obj.GetType().GetProperties()) {
FillObject(property, obj);
}
return obj;
}
private
void FillObject(PropertyInfo property, object obj) {
// Identify Custom attribute
SourceMapAttribute attribute =
(SourceMapAttribute)Attribute.GetCustomAttribute(
property, typeof(SourceMapAttribute));
if (attribute != null) {
// Check propertyName
/*Put your desired code and logic here.*/
if (attribute.PropertyName != string.Empty) {
/*Put your desired code and logic here.
I have simply demonstrated with one attribute property,
you can have as many as you like, and can perform any complex operation
you prefer.*/
// Get Source Object Value
object sourceValue = GetSourceValue(attribute.PropertyName);
if (property.CanWrite) {
// Assign source value to the mapped property
property.SetValue(obj, sourceValue, null);
}
}
Type propertyType = property.PropertyType;
object propertyInstance = property.GetValue(obj, null);
if (propertyInstance == null) {
// Instantiate when Property is not instantiated
propertyInstance = Activator.CreateInstance(property.PropertyType);
if (property.CanWrite) property.SetValue(obj, propertyInstance, null);
}
foreach (PropertyInfo info in propertyType.GetProperties()) {
// recursive call
FillObject(info, propertyInstance);
}
}
}
private
object GetSourceValue(string propertyName) {
if (SourceObject == null) {
SourceDataProvider provider = new SourceDataProvider();
this.SourceObject = provider.GetSource();
}
switch (propertyName) {
case "FirstName":
return SourceObject.FirstName;
case "LastName":
return SourceObject.LastName;
case "ContactAddress":
return this.SourceObject.ContactAddress;
case "ContactPhone":
return this.SourceObject.ContactPhone;
case "ContactMobile":
return this.SourceObject.ContactMobile;
case "ShippingAddress":
return this.SourceObject.ShippingAddress;
case "ShippingPhone":
return this.SourceObject.ShippingPhone;
case "ShippingMobile":
return this.SourceObject.ShippingMobile;
default:
return string.Empty;
}
}
}
Its worth talking a little bit about the above code snippet, all it does is takes an instance of the target class, uses reflection to loop through all its properties, while doing that identifies the custom attributes, checks for the mapping property and assigns values from the Source. This also creates property instances as required and recursively keeps working until all the properties ( including all descendents ) are checked and served.
Lets look at this Transformer in action.
Serve Client 1:
Here is what we see after transformation.
Serve Client 2:
and here is the result.
In this way we can serve any clients objects in any structure (considering, mapping is done properly). You will sure agree with me Transforming one object to another by taking advantage of .NET Attribute and .NET Reflection is quite cool. Thank you for being with me so far, Happy coding 🙂