しばらく頭を悩ませてきましたが、何かが足りないと思いますので、誰か助けてくれるかもしれません。
次のマッパークラスがあるとしましょう。
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");
そして最後に、DataTableとMappingConfigurationを入力として受け取り、IEnumerable<TestClass>
出力として生成するMappingEngineクラスをいくつか作成します。
アップデート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:式は書き込み可能である必要があります
パラメーター名:左