2016-07-08 8 views
0

データベースからデータ型へのマッピングパラメータを処理する次のコードを記述しました(標準ORMを使用することはできますが、多くの理由)式を使用してパラメータを設定する方法<Func<T>>

public void LoadDatabaseValue<T>(DataTable partData, string identifier, string mappingName, Expression<Func<T>> mappingProperty) 
    { 
     var partAttributeValue = mappingProperty.Name; 
     var memberExpression = (MemberExpression)mappingProperty.Body; 
     var prop = (PropertyInfo)memberExpression.Member; 
     try 
     { 
      var selectedRow = partData.Select($"partattributename = '{mappingName}'"); 
      var selectedValue = selectedRow[0]["PartAttributeValue"]; 

      var typedOutput = (T)Convert.ChangeType(selectedValue, typeof(T)); 

      prop.SetValue(memberExpression.Expression, typedOutput, null); 
     } 
     catch (Exception exception) 
     { 
      _databaseImportError = true; 
      // code to log this error 
    } 

私はこれを実行しようとすると、私は私の財産の種類と、それ私のtypedOutputラインをデバッグする、それが投げている理由は、私がわからないときは、私は次の例外

{System.Reflection.TargetException: Object does not match target type. 
at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target) 
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture) 
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index) } 

を取得この例外。

私はSetValueの最初のパラメータが値を設定するプロパティを含むオブジェクトである必要があります例えば

LoadDatabaseValue(partData, identifier, "Offset",() => Offset); 
+0

あなたは 'Func'を渡すが、それは'式> 'であることを期待しています。どちらかを同じタイプに変更してください。 – Venky

+1

@Venky彼は式を渡しています。 – Servy

答えて

1

、あなたが何らかの形で呼び出すことができるようにするためにmemberExpression.Expressionを評価する方法が必要ですSetValueメソッド。

ので、ラインに

prop.SetValue(Evaluate(memberExpression.Expression), typedOutput, null); 

prop.SetValue(memberExpression.Expression, typedOutput, null); 

を変更して、次の実装の1つを使用します。

(A)あなたが唯一のプロパティアクセサを使用する場合、これは十分であろう。

static object Evaluate(Expression e) 
{ 
    if (e == null) return null; 
    var me = e as MemberExpression; 
    if (me != null) 
     return ((PropertyInfo)me.Member).GetValue(Evaluate(me.Expression), null); 
    return ((ConstantExpression)e).Value; 
} 

(B)この1つは、より普遍的であるが、より低速:

static object Evaluate(Expression e) 
{ 
    if (e == null) return null; 
    return Expression.Lambda(e).Compile().DynamicInvoke(); 
} 
0

でそれを呼び出しています。

var obj = new TEntity(); 
prop.SetValue(obj, typedOutput); // From .NET 4.5 there is an overload with just 2 parameters 

obj.Offsetは、望ましい値を持つ必要があります。

したがって、プロパティを含むオブジェクトのタイプとプロパティ自体のタイプ(intstringなど)があります。

したがって、あなたの表現は次のようにする必要があります:

Expression<Func<TEntity, object>> mappingProperty 
TEntityは、オブジェクトの型である

objectは、このオブジェクトのプロパティの未知のタイプです。あなたは、事前に施設の種類を知っている限り、あなたは

Expression<Func<TEntity, TProperty>> mappingProperty 

を持つことになり、その場合にはあなたがこのようにそれを呼び出します。

LoadDatabaseValue(partData, identifier, "Offset", x => x.Offset); 

selectedValueがある場合を除きます。このようなタイプを(変更する必要がありますすでに正しいタイプの):あなたは、現在のメソッドの設計を維持したい場合は

object typedOutput = Convert.ChangeType(selectedValue, prop.PropertyType); 
+0

私はこれを実装しようとしましたが、署名のLoadDatabaseValue(partData、identifier、 "Offset"、x => x.Offset);コンパイルされませんでした。提示された他のソリューションよりも、この方法の利点は何ですか? – PlTaylor

+0

タイプ 'TEntity'は' Offset'プロパティを持っていなければなりません。あなたは 'memberExpression.Expression'の値を設定しようとしています。しかし、この表現には実際の表現に関するメタ情報だけが含まれており、実際のオブジェクトそのものを表すものではありません。私はあなたがしようとしていることを完全に理解していませんが、私はこのようなメソッドを宣言します: 'public void LoadDatabaseValue (DataTable partData、TEntityエンティティ、文字列マッピング名、式> mappingProperty)'エンティティオブジェクトの1つのプロパティを満たすために 'prop.SetValue(entity、typedOutput); –

+0

また、 'typedOutput'には正しい型の値が含まれていなければなりませんが、' SetValue'のパラメータ型は 'object'なので、' object'とタイプすることもできます。 –

関連する問題