65.9K
CodeProject is changing. Read more.
Home

Simple Model/Entity Mapper in C#

Sep 2, 2014

CPOL

1 min read

viewsIcon

53705

downloadIcon

387

Let’s see how to make a simple model or Entity mapper using reflections in C#

Introduction

When working in C#, we may want to map one Model/Entity to another. Reflection is the key which can help us at this point.

So let’s see how to make a simple model or Entity mapper using reflections in C#.

Background

Let’s say we have some models like:

IStudent Interface

interface IStudent
{
    long Id { get; set; }
    string Name { get; set; }
}

Student Class

class Student : IStudent
{
    public long Id { get; set; }
    public string Name { get; set; }
}

StudentLog Class

class StudentLog : IStudent
{
    public long LogId { get; set; }
    public long Id { get; set; }
    public string Name { get; set; }
}

Where Student and StudentLog, both have some common properties (name and type is the same).

MapperUtility

Here is the utility class which we are going to use for mapping:

TTarget MapTo<TSource, TTarget> (this TSource aSource, TTarget aTarget) - maps properties of aSource to given aTarget, and returns the aTarget

TTarget CreateMapped<TSource, TTarget> (this TSource aSource) - maps properties of aSource to a newly created object of type TTarget and returns it

Mapping would work for the properties where name and type are the same for TSource and TTarget.

public static class MapperUtility
{
    /*passing values to given object*/
    public static TTarget MapTo<TSource, TTarget>(this TSource aSource, TTarget aTarget)
    {
        const BindingFlags flags = BindingFlags.Public | 
                                 BindingFlags.Instance | BindingFlags.NonPublic;
       
        /*TODO: find fields*/
        var srcFields = (from PropertyInfo aProp in typeof(TSource).GetProperties(flags)
                           where aProp.CanRead     //check if prop is readable
                             select new
                             {
                                 Name = aProp.Name,
                                 Type = Nullable.GetUnderlyingType(aProp.PropertyType) ?? 
                                                                        aProp.PropertyType
                             }).ToList();
        var trgFields = (from PropertyInfo aProp in aTarget.GetType().GetProperties(flags)
                             where aProp.CanWrite   //check if prop is writeable
                                 select new
                                 {
                                     Name = aProp.Name,
                                     Type = Nullable.GetUnderlyingType(aProp.PropertyType) ?? 
                                                                         aProp.PropertyType
                                 }).ToList();

        /*TODO: common fields where name and type same*/
        var commonFields = srcFields.Intersect(trgFields).ToList();

        /*assign values*/
        foreach (var aField in commonFields)
        {
            var value = aSource.GetType().GetProperty(aField.Name).GetValue(aSource, null);
            PropertyInfo propertyInfos = aTarget.GetType().GetProperty(aField.Name);
            propertyInfos.SetValue(aTarget, value, null);
        }
        return aTarget;
    }

    /*returns new object with mapping*/
    public static TTarget CreateMapped<TSource, TTarget>(this TSource aSource) where TTarget : new()
    {
        return aSource.MapTo(new TTarget());
    }
}

Create New Mapped

Would create new mapped object of StudentLog from object source of type Student:

Student source = new Student() { Id = 1, Name = "Smith" };
/*get new object, which been mapped*/
StudentLog newMapped = source.CreateMapped<Student, StudentLog>();

Map to Existing One

Would map from target of type Student to an existing aSourceLog of type StudentLog:

/*map to existing object*/
StudentLog aSourceLog = new StudentLog();
Student target = new Student();
target.Id = 2;
target.Name = "Tom";

aSourceLog = target.MapTo(aSourceLog);
//or
target.MapTo(aSourceLog);

Limitations

  1. I have used framework 4.
  2. This mapper only works for classes. If you try with struct, it wouldn’t be able to map, or if you try to use List<Student>, it would throw an error.
  3. I only needed that much so I created it, if you need to do some more things, check out AutoMapper.

You can find the solution of VS2010 in the attachment.