使用c#表达式树,我可以创建一个匿名到类型化的对象映射
本文关键字:一个 类型化 映射 对象 表达式 我可以 创建 使用 | 更新日期: 2023-09-27 18:10:18
这是在数据层上,所以性能非常重要。否则我会使用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();
}
<<p> 当前问题/strong> - 我如何将setter组合成一个返回编译委托?
- 我如何创建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>
类中的一个私有函数-我把它放在一个单独的类中只是为了显示原始问题的答案。
MapFunc<TInput, TOutput>
类是一个单例,作为编译函数委托的缓存。
Unit<T>
充当中介,并且(与扩展方法一起)需要允许推断传递的匿名对象的类型并仅指定目标类型。