65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中的简单模型/实体映射器

2014年9月2日

CPOL

1分钟阅读

viewsIcon

54221

downloadIcon

420

让我们看看如何使用反射在 C# 中创建一个简单的模型或实体映射器

引言

在 C# 中工作时,我们可能希望将一个模型/实体映射到另一个模型/实体。 反射是可以在此时帮助我们的关键。

所以让我们看看如何使用反射在 C# 中创建一个简单的模型或实体映射器。

背景

假设我们有一些模型,例如

IStudent 接口

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

Student 类

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

StudentLog 类

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

其中 Student StudentLog 都具有一些公共属性(名称和类型相同)。

MapperUtility

这是我们将用于映射的实用工具类

TTarget MapTo<TSource, TTarget> (this TSource aSource, TTarget aTarget) - 将 aSource 的属性映射到给定的 aTarget,并返回 aTarget

TTarget CreateMapped<TSource, TTarget> (this TSource aSource) - 将 aSource 的属性映射到类型为 TTarget 的新创建的对象,并返回它

映射将适用于 TSource TTargetnametype 相同的属性。

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());
    }
}

创建新的映射

将从类型为 Student 的对象源创建新的 StudentLog 映射对象

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

映射到现有对象

将从类型为 Student 的目标映射到类型为 StudentLog 的现有 aSourceLog

/*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);

限制

  1. 我使用了框架 4。
  2. 此映射器仅适用于类。 如果您尝试使用 struct,它将无法映射,或者如果您尝试使用 List<Student>,它将引发错误。
  3. 我只需要这么多,所以我创建了它,如果您需要做更多的事情,请查看 AutoMapper

您可以在附件中找到 VS2010 的解决方案。

© . All rights reserved.