11

ラムダ式 (以下) を介して割り当てることができれば、これは非常に簡単です。

//An expression tree cannot contain an assignment operator
Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[0].FirstName = "Tim";

上記のコードは代入演算子のため無効です。設定が必要な複合オブジェクト内のプロパティを識別するために、ラムダ式を渡す必要があります。場合によっては、複雑なオブジェクトに List が含まれているため、オブジェクトの種類と名前が重複しているため、更新するオブジェクトのフィールドを明示的に参照するにはラムダが必要です。

以下を使用して値を取得できますが、問題ありません。しかし、この同じロジックを使用して値を設定する方法がわかりません.Expression.Assignに出くわし、これが解決策であると信じています.

Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[0].FirstName;
var result = FindByProperty(expression);

public static string FindByProperty(Expression<Func<Contract, object>> propertyRefExpr)
{
    ComplexObj obj = new ComplexObj();
    Contact myContact = new Contact();
    myContact.FirstName = "Allen";
    obj.Contacts = new List<Contact>{myContact};
    return propertyRefExpr.Compile().Invoke(obj);
}

アップデート:

「プロパティの割り当てを式ツリーとしてメソッドに渡します...」

ParentTypeA で SetValue メソッドを使用すると、Value は機能しません。(コードの下)

Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[0].FirstName;
obj.AssignNewValue(expression, firstName);

public static void AssignNewValue(this ComplexObj obj, Expression<Func<ComplexObj, object>> expression, object value)
{
    var propertyInfo = (PropertyInfo)((MemberExpression)expression.Body).Member;
    propertyInfo.SetValue(obj, value, null);
}
4

2 に答える 2

16

私は次の解決策を使用することになりました。乾杯

ComplexObj obj = new ComplexObj();
Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[index].FirstName;
obj.AssignNewValue(expression, firstName);

public static void AssignNewValue(this ComplexObj obj, Expression<Func<ComplexObj, object>> expression, object value)
{
    ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object));
    Expression targetExpression = expression.Body is UnaryExpression ? ((UnaryExpression)expression.Body).Operand : expression.Body;

    var newValue = Expression.Parameter(expression.Body.Type);
    var assign = Expression.Lambda<Action<ComplexObj, object>>
                (
                    Expression.Assign(targetExpression, Expression.Convert(valueParameterExpression, targetExpression.Type)),
                    expression.Parameters.Single(),
                    valueParameterExpression
                );

    assign.Compile().Invoke(obj, value);
}
于 2012-12-08T02:35:26.623 に答える
0

リンク先の質問はおそらく「正しい」答えですが、完全を期すために、このようなことをもっと行うことができます...「教えて、尋ねないで」方法論にもう少しよく従いますが、私は実装が好きとは言えません...

void Main()
{
    Expression<Func<ComplexObj, object>> expression = 
      obj => obj.Contacts[0].SetFirstName("Tim");       
}

public class ComplexObj
{
    public ComplexObj() { Contacts = new List<SimpleObj>(); }
    public List<SimpleObj> Contacts {get; private set;}
}
public class SimpleObj
{
    public string FirstName {get; private set;}
    public SimpleObj SetFirstName(string name) { this.FirstName = name; return this; }
}
于 2012-12-07T22:17:44.490 に答える