ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – 将一个对象属性值转移到另一个对象属性值

2019-06-09 23:56:43  阅读:495  来源: 互联网

标签:c mapping reflection-emit system-reflection ilgenerator


最重要的是,我知道AutoMapper,我不想使用它.因为我正在学习C#而我想深入了解它.所以我想尝试自己做这个问题(下面解释).

但是,我正在尝试创建一个属性复制器来处理一种类型属性的值到另一种属性,如果该属性具有相同的名称和类型,并且可以从源中读取并在目标中可写.我正在使用type.GetProperties()方法.采样方法如下:

    static void Transfer(object source, object target) {

        var sourceType = source.GetType();
        var targetType = target.GetType();

        var sourceProps = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

        var targetProps = (from t in targetType.GetProperties()
                           where t.CanWrite
                                 && (t.GetSetMethod().Attributes & MethodAttributes.Static) == 0
                           select t).ToList();

        foreach(var prop in sourceProps) {
            var value = prop.GetValue(source, null);
            var tProp = targetProps
                .FirstOrDefault(p => p.Name == prop.Name &&
                    p.PropertyType.IsAssignableFrom(prop.PropertyType));
            if(tProp != null)
                tProp.SetValue(target, value, null);
        }
    }

它有效,但我在SO上读到了一个答案,即使用System.Reflection.Emit和ILGenerator以及后期委托更快,性能更高.但没有更多的解释或任何链接.你能帮我理解加速这段代码的方法吗?或者你能告诉我一些关于Emit,ILGenerator和后期代表的链接吗?或者你认为有什么能帮到我?提前致谢.

COMPELETE Q:

我从@ svick的回答中了解并学到很多东西.但是现在,如果我想将它用作开放式通用方法,我该怎么做呢?这样的事情:

public TTarget Transfer<TSource, TTarget>(TSource source) where TTarget : class, new() { } 

或者延期:

public static TTarget Transfer<TSource, TTarget>(this TSource source) where TTarget : class, new() { } 

解决方法:

您可以使用Reflection.Emit来执行此操作,但使用表达式通常会更容易,它可以为您提供基本相同的性能.请记住,仅当您缓存已编译的代码时才会有性能优势,例如在Dictionary< Tuple< Type,Type>,Action< object,object>>中,我在这里没有这样做.

static void Transfer(object source, object target)
{
    var sourceType = source.GetType();
    var targetType = target.GetType();

    var sourceParameter = Expression.Parameter(typeof(object), "source");
    var targetParameter = Expression.Parameter(typeof(object), "target");

    var sourceVariable = Expression.Variable(sourceType, "castedSource");
    var targetVariable = Expression.Variable(targetType, "castedTarget");

    var expressions = new List<Expression>();

    expressions.Add(Expression.Assign(sourceVariable, Expression.Convert(sourceParameter, sourceType)));
    expressions.Add(Expression.Assign(targetVariable, Expression.Convert(targetParameter, targetType)));

    foreach (var property in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        if (!property.CanRead)
            continue;

        var targetProperty = targetType.GetProperty(property.Name, BindingFlags.Public | BindingFlags.Instance);
        if (targetProperty != null
                && targetProperty.CanWrite
                && targetProperty.PropertyType.IsAssignableFrom(property.PropertyType))
        {
            expressions.Add(
                Expression.Assign(
                    Expression.Property(targetVariable, targetProperty),
                    Expression.Convert(
                        Expression.Property(sourceVariable, property), targetProperty.PropertyType)));
        }
    }

    var lambda =
        Expression.Lambda<Action<object, object>>(
            Expression.Block(new[] { sourceVariable, targetVariable }, expressions),
            new[] { sourceParameter, targetParameter });

    var del = lambda.Compile();

    del(source, target);
}

如果你有这个,写你的通用方法是简单的:

public TTarget Transfer<TSource, TTarget>(TSource source)
    where TTarget : class, new()
{
    var target = new TTarget();
    Transfer(source, target);
    return target;
} 

使主工作方法也是通用的并创建Action< TSource,TTarget>或者甚至让它直接创建对象并使用Func< TSource,TTarget>可能是有意义的.但是,如果按照我的建议添加缓存,则意味着您必须使用类似Dictionary< Tuple< Type,Type>,Delegate>并在从缓存中检索委托后将委托转换为正确的类型.

标签:c,mapping,reflection-emit,system-reflection,ilgenerator
来源: https://codeday.me/bug/20190609/1208079.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有