簡體   English   中英

如何為類的每個屬性創建lambda表達式

[英]How to create lambda expressions for every property of a class

我有以下問題。 我必須遍歷該類的所有屬性以配置一些生成器。 類具有很多屬性,因此代碼很繁瑣。 看起來像這樣:

var b = builder<MyTypeWith1000Properties>
    .WithProperty(x=>x.Property1)
    .WithProperty(x=>x.Property2)
    ...
    .WithProperty(x=>x.Property1000);

對於許多不同類型,不僅在MyTypeWith1000Properties上,在許多地方都重復了該代碼。 我正在考慮創建一些擴展,例如:

var b = builder<MyTypeWith1000Properties>
    .WithAllProperties();

然后在WithAllProperties中,我可以使用Reflection遍歷類型屬性,如下所示:

public static IDataExtractor<T> WithAllProperties(this IDataExtractor<T> extractor)
{
    var properties = typeof(T).GetProperties();
    foreach (var property in properties)
    {
        extractor = extractor.WithProperty(/*the problem is here/*);
    }
    return extractor;
}

如何將循環中的屬性變量轉換為相應的表達式

Expression<Func<TRow, TValue>> propertyExpression

因為這是WithProperty期望的

更新-在Expression.Lambda>中設置正確的參數值

你可以嘗試這樣的事情

public static class BuilderExtension
{
    public static IDataExtractor<T> WithAllProperties<T>(this IDataExtractor<T> extractor)
    {
        var properties = typeof(T).GetProperties();
        foreach (var propertyInfo in properties)
        {
            var parameter = Expression.Parameter(typeof(T), "x");
            var property = Expression.Property(parameter, propertyInfo);
            var lambda = Expression.Lambda<Func<T, object>>(property,parameter);
            extractor = extractor.WithProperty(lambda);
        }
        return extractor;
    }
}

假設您具有以下類結構

public class MyTypeWith100Properties
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
    public string Property4 { get; set; }
}


public interface IDataExtractor<T>
{
    IDataExtractor<T> WithProperty(Expression<Func<T, object>> expr);
}

public class DataExtractor<T> : IDataExtractor<T>
{
    public List<Expression<Func<T, object>>> Expressions { get; private set; }

    public DataExtractor() {
        Expressions = new List<Expression<Func<T, object>>>();
    }
    public IDataExtractor<T> WithProperty(Expression<Func<T, object>> expr)
    {
        Expressions.Add(expr);
        return this;
    }
}

那如果你運行這個

var builder = new DataExtractor<MyTypeWith100Properties>();
var b = builder.WithAllProperties<MyTypeWith100Properties>() 
                         as DataExtractor<MyTypeWith100Properties>;

var instance = new MyTypeWith100Properties() {
                        Property1 = "This is property 1",
                        Property2 = "This is property 2",
                        Property3 = "This is property 3",
                        Property4 = "This is property 4"
                    };

foreach (var current in b.Expressions)
{
    var compiled = current.Compile();
    var result = compiled.Invoke(instance);
    Console.WriteLine(result);
}

您的輸出將是

這是物業1

這是物業2

這是物業3

這是物業4

WithProperty是一種通用方法,它采用屬性成員訪問表達式的結果類型所隱含的類型參數,這是TValue在其聲明中表示的內容。 由於要使用反射生成lambda,因此還必須動態進行WithProperty調用,以便可以使用正確的類型(例如,對於String屬性使用WithProperty<String>進行調用。

這是一個擴展方法,該方法生成一個lambda,該lambda由對一個類中所有屬性的所有鏈式WithProperty調用組成,然后編譯並調用IDataExtractor上的IDataExtractor 我將所有調用鏈接在一起,然后進行編譯,因為可能會有一些編譯開銷,所以我不想單獨編譯和調用每個屬性的代碼。

public static class IDataExtractorExt {
    public static IDataExtractor<TRow> WithAllProperties<TRow>(this IDataExtractor<TRow> extractor) {
        var p = Expression.Parameter(typeof(IDataExtractor<TRow>), "p"); // final lambda parameter
        Expression ansBody = p; // start with p => p

        var withPropGenericMI = typeof(IDataExtractor<TRow>).GetMethod("WithProperty"); // lookup WithProperty<> generic method
        var properties = typeof(TRow).GetProperties();
        foreach (var property in properties) {
            var withPropMI = withPropGenericMI.MakeGenericMethod(property.PropertyType); // instantiate generic WithProperty<> to property type
            var pxp = Expression.Parameter(typeof(TRow), "x"); // property accessor lambda parameter
            var pxb = Expression.PropertyOrField(pxp, property.Name); // property accessor expression x.property
            Expression propExpr = Expression.Lambda(pxb, pxp); // x => x.property
            ansBody = Expression.Call(ansBody, withPropMI, propExpr); // build up p => p.WithProperty(x => x.property)...
        }

        return ((IDataExtractor<TRow>)(Expression.Lambda(ansBody, p).Compile().DynamicInvoke(extractor)));
    }
}

暫無
暫無

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

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