我有以下问题。我必须遍历该类的所有属性以配置一些生成器。类具有很多属性,因此代码很繁琐。看起来像这样:
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期望的
答案 0 :(得分:0)
您可以尝试这样的事情
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
答案 1 :(得分:0)
WithProperty
是一种通用方法,它采用属性成员访问表达式的结果类型所隐含的类型参数,这就是TValue
在其声明中表示的含义。由于您要使用反射来生成lambda,因此还必须动态进行WithProperty
调用,以便您可以使用正确类型的调用(例如,WithProperty<String>
用于String
属性)。
这里是一个扩展方法,该方法生成一个lambda,该lambda由对类中所有属性的所有链接的WithProperty
调用组成,然后编译并调用IDataExtractor
上的lambda。我将所有调用链接在一起,然后进行编译,因为可能会有一些编译开销,所以我不想单独编译和调用每个属性的代码。
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)));
}
}