簡體   English   中英

創建一個屬性設置器委托

[英]Creating a property setter delegate

我創建了將屬性lambda轉換為委托的方法:

public static Delegate MakeGetter<T>(Expression<Func<T>> propertyLambda)
{
    var result = Expression.Lambda(propertyLambda.Body).Compile();
    return result;
}

public static Delegate MakeSetter<T>(Expression<Action<T>> propertyLambda)
{
    var result = Expression.Lambda(propertyLambda.Body).Compile();
    return result;
}

這些工作:

Delegate getter = MakeGetter(() => SomeClass.SomeProperty);
object o = getter.DynamicInvoke();

Delegate getter = MakeGetter(() => someObject.SomeProperty);
object o = getter.DynamicInvoke();

但是這些不會編譯:

Delegate setter = MakeSetter(() => SomeClass.SomeProperty);
setter.DynamicInvoke(new object[]{propValue});

Delegate setter = MakeSetter(() => someObject.SomeProperty);
setter.DynamicInvoke(new object[]{propValue});

MakeSetter行失敗,並顯示“無法從用法中推斷出類型實參。嘗試顯式指定類型實參。”

我想做的事可能嗎? 提前致謝。

Expression API在.NET 4.0中支持此功能,但遺憾的是C#編譯器沒有添加任何額外的支持。 但是好消息是,您可以輕松采用“ get”表達式(C#編譯器可以編寫)並將其重新編寫為“ set”表達式。

甚至更好; 如果您沒有.NET 4.0,那么至少還有至少兩種其他方式可以通過寫為“ get”的表達式來執行“ set”。

這里都是,以供參考:

using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo {
    public string Bar { get; set; }
    static void Main() {
        // take a "get" from C#
        Expression<Func<Foo, string>> get = foo => foo.Bar;

        // re-write in .NET 4.0 as a "set"
        var member = (MemberExpression)get.Body;
        var param = Expression.Parameter(typeof(string), "value");
        var set = Expression.Lambda<Action<Foo, string>>(
            Expression.Assign(member, param), get.Parameters[0], param);

        // compile it
        var action = set.Compile();
        var inst = new Foo();
        action(inst, "abc");
        Console.WriteLine(inst.Bar); // show it working

        //==== reflection
        MethodInfo setMethod = ((PropertyInfo)member.Member).GetSetMethod();
        setMethod.Invoke(inst, new object[] { "def" });
        Console.WriteLine(inst.Bar); // show it working

        //==== Delegate.CreateDelegate
        action = (Action<Foo, string>)
            Delegate.CreateDelegate(typeof(Action<Foo, string>), setMethod);
        action(inst, "ghi");
        Console.WriteLine(inst.Bar); // show it working
    }
}

根據我的評論-由於鏈接失效-我已發布完整代碼作為問題的答案。 是的,可以執行OP要求的操作 這是尼克(Nick)展示的一個漂亮的小寶石。 Nick將此頁面和另一頁歸功於他的完整解決方案以及性能指標。 我在下面提供了它,而不僅僅是一個鏈接

// returns property getter
public static Func<TObject, TProperty> GetPropGetter<TObject, TProperty>(string propertyName)
{
    ParameterExpression paramExpression = Expression.Parameter(typeof(TObject), "value");

    Expression propertyGetterExpression = Expression.Property(paramExpression, propertyName);

    Func<TObject, TProperty> result =
        Expression.Lambda<Func<TObject, TProperty>>(propertyGetterExpression, paramExpression).Compile();

    return result;
}

// returns property setter:
public static Action<TObject, TProperty> GetPropSetter<TObject, TProperty>(string propertyName)
{            
    ParameterExpression paramExpression = Expression.Parameter(typeof(TObject));

    ParameterExpression paramExpression2 = Expression.Parameter(typeof(TProperty), propertyName);

    MemberExpression propertyGetterExpression = Expression.Property(paramExpression, propertyName);

    Action<TObject, TProperty> result = Expression.Lambda<Action<TObject, TProperty>>
    (
        Expression.Assign(propertyGetterExpression, paramExpression2), paramExpression, paramExpression2
    ).Compile();

    return result;
}

Action<T>表示一個委托,該委托采用類型T一個參數,但不返回任何內容。 提供給MakeSetter的lambda表達式表示不帶參數的委托,並返回SomeClass.SomePropertysomeObject.SomeProperty

您收到的錯誤消息是由於以下事實:編譯器無法從傳遞給MakeSetter方法的lambda表達式中推斷類型,因為您傳遞的內容與該方法期望的內容不同步。

您的MakeSetter期望有一個Action<T>並且您要傳遞給它一個Func<T>() => someObject.SomeProperty )。 請嘗試以下操作:

Delegate setter = MakeSetter((prop) => {someObject.SomeProperty = prop;});
setter.DynamicInvoke(new object[]{propValue});

編輯看起來您無法將lambdas語句轉換為表達式 這是不使用表達式的某種方式的回合-直接針對委托人:

class Test2 {
    delegate void Setter<T>(T value);

    public static void Test() {
        var someObject = new SomeObject();
        Setter<string> setter = (v) => { t.SomeProperty = v; };
        setter.DynamicInvoke(new object[]{propValue});
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM