我已经弯曲了一段时间,但我想我错过了一些东西,所以可能有人会提供帮助。
假设我有以下映射器类:
public class Mapping<TSource, TResult>
{
private readonly Action<TSource, TResult> setter;
public Mapping(Expression<Func<TSource, TResult>> expression)
{
var newValue = Expression.Parameter(expression.Body.Type);
var body = Expression.Assign(expression.Body, newValue);
var assign = Expression.Lambda<Action<TSource, TResult>>(body, expression.Parameters[0], newValue);
setter = assign.Compile();
}
public void Assign(TSource instance, TResult value)
{
setter(instance, value);
}
}
它工作正常:
[Test]
public void ShouldMapProperty()
{
var testClass = new TestClass();
var nameMapping = new Mapping<TestClass, string>(x => x.Name);
var ageMapping = new Mapping<TestClass, int>(x => x.Age);
nameMapping.Assign(testClass, "name");
ageMapping.Assign(testClass, 10);
Assert.AreEqual("name", testClass.Name);
Assert.AreEqual(10, testClass.Age);
}
问题是,我想将单个对象类型的映射保留到某个集合中,而 TResult 会妨碍,只要不同的属性具有不同的类型。如何很好地摆脱 TResult?
更新: 看起来我不够清楚,所以这将是我将如何使用它的示例:
public class Mapping<TSource, TResult>
{
private readonly Action<TSource, TResult> setter;
private readonly string columnName;
public Mapping(Expression<Func<TSource, TResult>> expression, string columnName)
{
this.columnName = columnName;
var newValue = Expression.Parameter(expression.Body.Type);
var body = Expression.Assign(expression.Body, newValue);
var assign = Expression.Lambda<Action<TSource, TResult>>(body, expression.Parameters[0], newValue);
setter = assign.Compile();
}
public void Assign(TSource instance, DataRow row)
{
setter(instance, row[columnName]);
}
}
然后我会有一些 MappingConfiguration 类,它可以让我这样做:
MappingConfiguration.For<TestClass>()
.Map(x => x.Name, "FirstName")
.Map(x => x.Age, "Age");
最后是一些 MappingEngine 类,它将 DataTable 和 MappingConfiguration 作为输入并IEnumerable<TestClass>
作为输出产生。
更新 2: 我已将初始版本修改为:
public class Mapping2<TSource>
{
private readonly Delegate setter;
public Mapping2(Expression<Func<TSource, object>> expression)
{
var newValue = Expression.Parameter(expression.Body.Type);
var body = Expression.Assign(expression.Body, newValue);
var assign = Expression.Lambda(body, expression.Parameters[0], newValue);
setter = assign.Compile();
}
public void Assign(TSource instance, object value)
{
setter.DynamicInvoke(instance, value);
}
}
它几乎可以工作。
几乎我的意思是它适用于引用类型属性,并且我得到了值类型属性:
System.ArgumentException:表达式必须是可写的
参数名称:左