.NET custom attributes technique allows us to associate metadata and information to our code entities, be it classes, properties, methods… When we associate an attribute to a code entity, we can later read it again using a technique called Reflection

Reflection itself could take several articles to cover, but I’ll try to show and explain the basic topics of it to be able to use attributes without being a guru in reflection.

For this article I’ve setup a fully functional console project in C# that implements all the necessary stuff to map values from one class to another without having to assign every property by hand…

If you’re the download and play style, you can start by downloading the project from my Bitbucket repository using this links:

Git repository: http://repo.joanvilarino.info/attributemappersample

Zip download: http://repo.joanvilarino.info/attributemappersample/downloads

But I recommend you to keep reading for a better explanation of what’s happening there! So, without further introduction… let’s get to business!

Utility of attributes

Maybe you have been using attributes without knowing it, or without thinking that you could make your own ones.

For example, if you have done some MVC you may be habited to this:

[HttpPost]
public ActionResult PostMethod() {
}

Or, maybe, when you need to serialize objects, you defined your class this way:

[System.Serializable]
public class MySerializableClass {
}

Well, these are just two of the many pre-made attributes .NET includes. Let’s give it a twist by creating our own ones for the mapper.

StaticMapper

The example we are going to see in this article, makes use of attributes to create a StaticMapper class that will allow us mapping data between entities. This is a useful solution for scenarios where, for example, you have database flat entities (POCO entities) that you want to map to your viewmodels.

Creating our attributes

To create our own attributes, all we need is defining classes for them, inheriting from System.Attribute.

For our sample project, we’ll need two classes:

  • MappableClassAttribute This attribute marks the class as mappable for our mapper, and tells it what is its sibling class.
  • MappedPropertyAttribute We’ll use this attribute to define property-wide aspects of every individual mapping.
  • Here is the code for both of them:

    [AttributeUsage(AttributeTargets.Class)]
    public class MappableClassAttribute : Attribute
    {
        private readonly Type _associatedType;
        public Type AssociatedType { get { return _associatedType; } }
    
        public MappableClassAttribute(Type sourceAndTargetType)
        {
            _associatedType = sourceAndTargetType;
        }
    }
    
    [AttributeUsage(AttributeTargets.Property)]
    public class MappedPropertyAttribute : Attribute
    {
        public string MapTo { get; set; }
    }
    

    First of all, notice the AttributeUsage attribute in both definitions (attributes in the attribute class, ain’t it funny?).

    The AttributeUsage restricts where you can place this attribute. It’s not mandatory, but if the attribute you’re defining is meant only for a class, a property or a method, for example, it’s a good practice to set its usage, so the compiler notifies us of non-allowed usages.

    I’ve used two different ways to implement the attributes. The first of them is using a constructor to initialize the property AssociatedType, while the second class doesn’t have constructor and it’s got a public auto-property.

    This difference applies at usage time. To use the first attribute we’ll do it this way:

    [MappableClass(typeof(MyPOCOEntity))]
    public class MyViewModel {
       ....
    }
    

    You can see there’s no property name implied, since it will use the primary constructor we defined for the attribute, while in the property attribute case is different:

       ...
       [MappedProperty(MapTo = "MyPropertyPOCO")]
       public string MyPropertyVM { get; set; }
       ...
    

    In this declaration, I’m forced to use the property name I’m setting because the attribute doesn’t have a defined constructor.

    Normally, you will define constructors for attributes where properties are required, and let without constructor when everything is optional. You can also combine both ways to do it.

    [MyAttrib("ForcedParam", OtherParam = true]
    

    Using the attributes in our ViewModel class

    Ok, we have our attributes, so it’s time to use them. Let’s create our ViewModel class. It will be a near identical copy of the POCO entity, but while the POCO entity uses a “DtoId” property, our ViewModel, for demonstration purposes will use “Id” instead.

    Here is the POCO entity:

    public class TestDto
    {
        public long DtoId { get; set; }
        public string Name { get; set; }
        public DateTime BirthDate { get; set; }
    }
    

    And here is the ViewModel with its attributes set:

    [MappableClass(typeof(TestDto))]
    public class TestViewModel
    {
        [MappedProperty(MapTo = "DtoId")]
        public long Id { get; set; }
        [MappedProperty]
        public string Name { get; set; }
        [MappedProperty]
        public DateTime BirthDate { get; set; }
    }
    

    Hey! What happened to the ...Attribute trailing part of our attributes? Well, by convention the attribute classes name are finished on Attribute, and .NET knows that anything inside brackets before the declaration of a code block must be an attribute, so it looks for the class name adding Attribute at the end. I guess it’s just a “visual” issue. If you write the complete name, it will work the same.

    Looking at this code it’s easy to notice that we are declaring a TestViewModel class that is mappable from the class TestDto, and its properties are mappable as well. We only have to specify MapTo property when the name of the property doesn’t match the name at the mapped class.

    Reading the attributes with Reflection

    We have our attributes in place, but that would be useless if we coulnd’t read them again. How is that done? We use Reflection for that.

    Reflection is a technique .NET implements that will allow us to access code declaration at run-time. That is, I can use an object’s instance to check what type it is, its inheritances, its properties, fields, methods, constructors and so on.

    To access reflection information we will use its type, accesible with typeof(type) or object.GetType(), and from the type we can get info about properties, methods, or anything, like this:

    PropertyInfo[] propsInfo = myObject.GetType().GetProperties();
    MethodInfo methodInfo = myObject.GetMethod("MyClassMethod");
    FieldInfo[] fieldsInfo = typeof(MyClass).GetFields();
    

    All the reflection info objects have methods to get the list of custom attributes attached to a piece of code. The most used are the following:

    • object[] GetCustomAttributes(inherit) Gets all custom attributes from a reflection info object.
    • object[] GetCustomAttributes(type, inherit) Gets all custom attributes of the type type.
    • T GetCustomAttribute(inherit) Gets the attribute of type T if present, or null if it’s not defined for that object.

    If we use a non-generic type to get the attribute, we’ll need to cast it to our class:

    var myAttr = myObj.GetType().GetProperty("MyProp")
                   .GetCustomAttributes(typeof(MyAttribute),false)
                   .FirstOrDefault() as MyAttribute;
    if (myAttr != null) {
       .....
    }
    

    Mapping

    Here is part of the implementation of the class StaticMapper, where we check if a type is mappable from another:

    public static bool IsMappableWith(this Type type, Type targetType)
    {
        // One of the types must have MappableClassAttribute pointing to the 
        // other. If not, we can't map that!
        var attrSource = type.GetCustomAttribute<MappableClassAttribute>(false);
        var attrTarget = targetType.GetCustomAttribute<MappableClassAttribute>();
        return (attrSource != null && attrSource.AssociatedType == targetType)
            || (attrTarget != null && attrTarget.AssociatedType == type);
    }
    

    And this is the main method that takes care of the mapping:

    public static TOut MapTo<TOut, TIn>(this TIn objIn, TOut objOut) 
        where TIn : class 
        where TOut : class 
    {
        // Is one class mappable to or from the other?
        if (!objIn.GetType().IsMappableWith(typeof(TOut)))
            throw new FormattedException("The types '{0}' and '{1}' are not mappable.",
                objIn.GetType().Name, objOut.GetType().Name);
    
        Type infoType = null;
        // The class defining the mappings is the "In" or the "Out" object?
        var attr = objIn.GetType().GetCustomAttribute<MappableClassAttribute>();
        if (attr != null)
            infoType = objIn.GetType();
        else
        {
            attr = typeof (TOut).GetCustomAttribute<MappableClassAttribute>();
            if (attr != null)
                infoType = typeof (TOut);
        }
    
        // Let's iterate the properties of the defining class searching for properties
        // with the attribute to map them
        infoType.GetProperties()
            .Where(p => p.GetCustomAttributes(typeof(MappedPropertyAttribute), false).Any())
            .ToList()
            .ForEach(p => MapValue(infoType, p, objIn, objOut));
    
        return objOut;
    }
    

    Finally, the MapValue method, takes care of reading and setting property values from one object to the other, calling Map to copy the value safely:

    private static void MapValue(Type infoType, PropertyInfo prop, object objIn, object objOut)
    {
        // Get our custom attribute
        var attr = prop.GetCustomAttribute<MappedPropertyAttribute>();
        // Check wether the mapping defining class is objIn or objOut, to know
        // the direction of the mapping... set the source and target properties
        // and call map to copy the value
        if (infoType == objOut.GetType())
        {
            var sourceProp = objIn.GetType().GetProperty(attr.MapTo ?? prop.Name);
            if (sourceProp != null)
                Map(sourceProp, objIn, prop, objOut);
        }
        else
        {
            var targetProp = objOut.GetType().GetProperty(attr.MapTo ?? prop.Name);
            if (targetProp != null)
                Map(prop, objIn, targetProp, objOut);
        }
    }
    
    private static void Map(PropertyInfo pIn, object objIn, PropertyInfo pOut, object objOut)
    {
        // First of all... the types should be compatibles.
        // Here you got a nice work to make the method able to convert. You could
        // add a ConverterClass property to the attribute an invoke it here...
        if (!pOut.PropertyType.IsAssignableFrom(pIn.PropertyType))
            throw new FormattedException("Can't map value from '{0}' ({1}) to '{2}' ({3}"
                , pIn.Name, pIn.PropertyType.Name, pOut.Name,pOut.PropertyType.Name);
        // Assign the value
        try
        {
            pOut.SetValue(objOut,pIn.GetValue(objIn,null));
        }
        catch (Exception ex)
        {
            throw new FormattedException("Error converting data from {0} to {1}", ex, pIn.Name, pOut.Name);
        }
    }
    

    Running things

    All set! let’s setup our test and make it run! it should be something like this:

    Console.WriteLine("{0}.IsMappableWith({1})         : {2}",
        typeof(TestViewModel).Name, 
        typeof(TestDto).Name, 
        typeof(TestViewModel).IsMappableWith(typeof(TestDto)));
    
    var dto = new TestDto()
    {
        DtoId = 20,
        BirthDate = DateTime.Today,
        Name = "TestSubject"
    };
    Console.WriteLine("Sample object               : {0} / {1} / {2}"
        , dto.DtoId, dto.Name, dto.BirthDate);
    
    var vm = dto.MapTo<TestViewModel>();
    Console.WriteLine("TestDTo > TestViewModel     : {0} / {1} / {2}",
         vm.Id, vm.Name,vm.BirthDate);
    
    vm.Name += "(Modified)";
    Console.WriteLine("Changed name to '{0}'.", vm.Name);
    
    var newDto = vm.MapTo<TestDto>();
    Console.WriteLine("TestViewModel > new TestDto : {0} / {1} / {2}",
        newDto.DtoId,newDto.Name,newDto.BirthDate);
    

    And here’s the result:
    mapper

    Thank you

    More stuff coming in short. I hope you have found it interesting! If not, visit my code repository at http://repo.joanvilarino.info

    Follow me

    Joan Vilariño

    Senior .NET Developer at Ohpen
    Developer for more than 25 years and IT, gadget, mobile and electronics enthusiast working and publishing from Barcelona.
    Follow me