c# - 使用 C# 表达式树,我可以创建一个匿名到类型化对象映射吗?

标签 c# lambda linq-expressions

这是在数据层上,因此性能非常重要。否则我会使用 Automapper。如果它是 IDBConnection,我会使用 Dapper。

我想将匿名对象的简单创作带到 POCO 中,并使用编译表达式来表达它。

代码

public class Foo
{
    public string Bar{get;set;}
    public string Baz{get;set;}
}

public void doStuff()
{
     var obj = new{Bar= "My Name, Baz = "Some other data"};

     //can I recreate this assignment to foo using expressions?
     var foo = new Foo{
         Bar = obj.Bar,
         Baz = obj.Baz
     }
}

(不完整)到目前为止我有...

var props = o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)

    foreach (var prop in props)
                {
                    var targetProp = typeof(T).GetProperty(prop.Name);
                    var targetExp = Expression.Parameter(typeof(T), "target");
                    var valueExp = Expression.Parameter(prop.PropertyType, "property");



                    var propExp = Expression.Property(targetExp, targetProp);
                    var assignExp = Expression.Assign(propExp, valueExp);

                    var setter = Expression.Lambda<Action<T, object>>(assignExp, targetExp, valueExp).Compile();
                }

当前问题

  1. 如何将 setter 组合成返回编译委托(delegate)?
  2. 在遍历属性时如何创建 Lambda[Action] 泛型类型?

感谢所有的输入。

最佳答案

给你:

using System;
using System.Linq;
using System.Linq.Expressions;

namespace Tests
{
    public static class Utils
    {
        public static Func<TInput, TOutput> CreateMapFunc<TInput, TOutput>()
        {
            var source = Expression.Parameter(typeof(TInput), "source");
            var body = Expression.MemberInit(Expression.New(typeof(TOutput)),
                source.Type.GetProperties().Select(p => Expression.Bind(typeof(TOutput).GetProperty(p.Name), Expression.Property(source, p))));
            var expr = Expression.Lambda<Func<TInput, TOutput>>(body, source);
            return expr.Compile();
        }
    }
    public static class MapFunc<TInput, TOutput>
    {
        public static readonly Func<TInput, TOutput> Instance = Utils.CreateMapFunc<TInput, TOutput>();
    }
    public struct Unit<T>
    {
        public readonly T Value;
        public Unit(T value) { Value = value; }
        public U MapTo<U>() { return MapFunc<T, U>.Instance(Value); }
    }
    public static class Extensions
    {
        public static Unit<T> Unit<T>(this T source) { return new Unit<T>(source); }
    }
    // Test
    public class Foo
    {
        public string Bar { get; set; }
        public string Baz { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var obj = new { Bar = "My Name", Baz = "Some other data" };
            //var foo = new Foo { Bar = obj.Bar, Baz = obj.Baz };
            var foo = obj.Unit().MapTo<Foo>();
        }
    }
}

如果有人对它的工作原理感兴趣:

主要部分是CreateMapFunc使用 MemberInitExpression 构建和编译 lambda 表达式的函数.它确实应该是 MapFunc<TInput, TOutput> 中的私有(private)函数class - 我把它放在一个单独的类中只是为了显示原始问题的答案。

MapFunc<TInput, TOutput>类是一个单例,并充当已编译函数委托(delegate)的缓存。

Unit<T>充当中间人并且(与扩展方法一起)需要允许推断传递的匿名对象的类型并仅指定目标类型。

关于c# - 使用 C# 表达式树,我可以创建一个匿名到类型化对象映射吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32288999/

相关文章:

c# - 可以读/写 .xls 文件的 .NET Excel 库

c# Listview 使用文本框搜索

c# - 如何获取lambda表达式的值

c# - 将 Linq 表达式添加到表达式列表的方法

c# - 如何在 C# 中创建嵌套(父子)JSON 响应?

c# - 如何在 C# 中使用 iTextSharp 获取 pdf 文件中的特定段落?

c# - 我可以将嵌入式 lambda 与 Contains 方法一起使用吗?

java - 是否可以构造一个 Java 流表达式来返回一个 2D boolean 数组,所有值都设置为 true?

entity-framework-core - 如何在 Entity Framework Core 中构建递归表达式树?

linq - 如何创建 Expression<Func<T, TRelated>> 的集合?