【问题标题】:Passing a list of Lamba expressions for accessing Properties传递用于访问属性的 Lambda 表达式列表
【发布时间】:2017-04-20 07:42:12
【问题描述】:

我今天有一个静态函数,我传递一个属性表达式并从中创建一个字符串:

public static string SomeFunction<TModel, TProperty>(TModel model, Expression<Func<TModel, TProperty>> expression){...}

我想改变它来处理这样的表达式列表:

static string SomeFunctionForList<TModel, TProperty>(TModel model, List<Expression<Func<TModel, TProperty>>> expressions){...}

在第二种情况下,我将遍历表达式并执行我正在对它们执行的任何逻辑。

这就是我现在调用函数的方式:

SomeFunction(this, m => m.nameOfProperty)

如何调用这个函数并定义表达式列表?我正在尝试这个,但它不起作用:

SomeFunctionForList(this,
                    new List<Expression<Func<TModel, TProperty>>> {
                        { m => m.nameOfProperty1},
                        { m => m.nameOfProperty2} 
});

我收到一个无法找到 TModel 和 TProperty 的编译器错误。需要明确的是,这是在不同的文件中调用的。

【问题讨论】:

  • 我不确定,但我的意思是“TModel”和“TProperty”不是类型。它们是通用参数。您必须将“TModel”替换为任何模型类型,将“TProperty”替换为任何属性类型。
  • 您遇到的问题是TProperty 会因每个属性而异吗?
  • 是的 - 基本上,我想发送一个模型和一个 Lamba 表达式列表,并让方法发挥它的魔力

标签: c# reflection lambda


【解决方案1】:

你有泛型方法SomeFunctionForList 和泛型类型参数TModelTProperty。在第一种情况下,类型推断能够从方法调用的第一个和第二个参数推断这些参数的类型。这就是您可以跳过显式指定类型参数的原因。

但类型推断仅适用于泛型方法。它不适用于从构造函数参数推断类型参数。这就是为什么您应该明确指定List&lt;T&gt; 通用参数的原因。注意:您应该指定类型名称而不是泛型参数。例如。如果TModelYourModel 类,并且两个属性都有string 类型,那么方法调用应该如下所示:

SomeFunctionForList(this,
           new List<Expression<Func<YourModel, string>>> {
                    { m => m.nameOfProperty1},
                    { m => m.nameOfProperty2} 
           });

因此,如果您想使用类型推断,此处不能选择使用列表构造函数。您可以使用params 指定可变数量的参数(作为数组传递)并具有类型推断的好处:

public static string SomeFunction<TModel, TProperty>(
    TModel model, params Expression<Func<TModel, TProperty>>[] expressions)

然后方法调用会是这样的

SomeFunctionForList(this,
              m => m.nameOfProperty1,
              m => m.nameOfProperty2
           );

请注意,属性应具有相同的类型。

【讨论】:

  • Gotcha - 在现实生活中,我在方法中的参数之后有几个参数,因此 params 不是一个理想的选择。有什么办法可以欺骗编译器跳过类型推断?
  • @Corez 你不能使用构造函数——类型推断在这里不起作用。您可以通过通用方法创建为您创建列表的工厂。元组使用相同的方法 - 可以调用工厂方法 Tuple.Create(4,"foo"),而不是调用 new Tuple&lt;int,string&gt;(4,"foo")。您的工厂可以简单为public static List&lt;T&gt; CreateList&lt;T&gt;(params T[] items) =&gt; items.ToList();,用法为SomeFunctionForList(this, Factory.CreateList(m =&gt; m.nameOfProperty1,m =&gt; m.nameOfProperty2))
【解决方案2】:

“TModel”和“TProperty”是泛型参数而不是类型。但是如果你想调用它,你必须输入任何模型类型和任何属性类型。

例如,这应该可以工作:

private string aStringProperty { get; set; }  
private int aIntegerProperty { get; set; }

-

SomeFunctionForList(this, new List<Expression<Func<Program, dynamic>>>{
                                                              { m => m.aStringProperty},
                                                              { m => m.aIntegerProperty}
                                                          });

就我而言,我使用动态作为属性。有了它,您可以使用不同类型的属性,但要小心!

【讨论】:

    【解决方案3】:

    需要指定类型参数,例如:

    SomeFunctionForList(t,
                    new List<Expression<Func<Thing, string>>> {
                        { m => m.StringProperty1},
                        { m => m.StringProperty2}
    });
    

    但是,这只允许您使用所有返回相同类型的属性,在本例中为 string。你可以改用object

    SomeFunctionForList(t,
                    new List<Expression<Func<Thing, object>>> {
                        { m => m.StringProperty},
                        { m => m.BoolProperty}
    });
    

    【讨论】:

      【解决方案4】:
      public static string SomeFunction<TModel, TProperty>(TModel model, params Expression<Func<TModel, TProperty>>[] expressions)
      

      【讨论】:

      • 我应该更清楚 - 我的意思是当我调用函数时问题正在发生。在该文件中,它无法识别 TModel 和 TPropoerty
      • 您必须解开方法并使用反射找出通用参数才能成功调用它们。没有方法源代码很难猜出错误。但我认为你应该能够通过反射来做到这一点。
      • 该错误是编译错误,调用者无法编译,因为找不到 TModel 和 TProperty。显然,因为它们是调用代码范围之外的泛型。
      • 公共静态对象 SomeFunction(TModel model, params Expression>[] 表达式) => 表达式.Select(e=>(e.Body as System .Linq.Expressions.MemberExpression).Member...);
      猜你喜欢
      • 1970-01-01
      • 2019-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多