【问题标题】:How to convert PropertyInfo to property expression and use it to invoke generic method?如何将 PropertyInfo 转换为属性表达式并使用它来调用泛型方法?
【发布时间】:2022-01-13 18:34:00
【问题描述】:

如何将PropertyInfo转换为属性表达式,可以用来调用StructuralTypeConfiguration<TStructuralType>.Ignore<TProperty>(Expression<Func<TStructuralType, TProperty>> propertyExpression)方法?

我尝试使用Expression.Property() 构造表达式,但是当我将此表达式用作propertyExpression 参数时出现以下错误:

The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly.

这个错误可能是指TProperty类型参数,我不知道如何指定只有PropertyInfo

我这样做是为了:Use Entity Framework's StructuralTypeConfiguration.Ignore() to Ignore all properties but specified set

更新

不工作的代码:

var propertyInfo = typeof(Foo).GetProperties()[0];
var expression = Expression.Default(typeof(Foo));
var expressionProperty = Expression.Property(expression, propertyInfo);
Ignore(expressionProperty);

【问题讨论】:

  • 您应该显示您的代码不起作用...

标签: c# .net linq system.reflection


【解决方案1】:
var entityType = propertyInfo.DeclaringType;
var parameter = Expression.Parameter(entityType, "entity");
var property = Expression.Property(parameter, propertyInfo);
var funcType = typeof(Func<,>).MakeGenericType(entityType, propertyInfo.PropertyType);
var lambda = Expression.Lambda(funcType, property, parameter);

structureConfiguration.GetType()
   .GetMethod("Ignore")
   .MakeGenericMethod(propertyInfo.PropertyType)
   .Invoke(structureConfiguration, new[]{lambda});

【讨论】:

  • 试过了,但收到The type or method has 1 generic parameter(s), but 2 generic argument(s) were provided. A generic argument must be provided for each generic parameter. 错误。 StackTrace:在 System.RuntimeType.SanityCheckGenericArguments(RuntimeType[] genericArguments, RuntimeType[] genericParamters) 在 System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation) 在 Here_is_this_code(DbModelBuilder modelBuilder)
  • 当我评论.MakeGenericMethod(...)时,我得到了Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.
  • 原来funcType是没有必要的。
【解决方案2】:

属性表达式要求对特定对象进行属性访问。您可以在这里选择几个选项。首先,如果这是在您的一个实体对象中完成的,您可以简单地使用 ConstantExpression 来构建属性表达式:

// Already have PropertyInfo in propInfo
Expression.Property(Expression.Constant(this, this.GetType()), propInfo)

但是,既然您需要Expression&lt;Func&lt;TStructuralType, TProperty&gt;&gt;,那么您似乎必须使用 ParameterExpression 来构建它:

ParameterExpression pe = Parameter.Expression(typeof(MyEntity), "eParam");
Expression propExp = Expression.Property(pe, propInfo);

但是,问题来了……这只是一个 MemberExpression。要转换为您需要的表达式,您需要使用Expression.Lambda 来获取您需要的类型的 Func 表达式。问题?你不知道定义 lambda 表达式的泛型参数的属性类型!

Expression<Func<MyEntity, ????>> eFunc = Expression.Lambda<Func<MyEntity, ????>>(propExp, pe);

这是问题的症结所在。这并不是说它不能完成......只是以这种方式使用这种方法是行不通的。您必须使用一些运行时和静态类型技巧(以及明智地使用 Actions 而不是 Funcs)才能使其正常工作。

【讨论】:

    【解决方案3】:

    TProperty 仅存在于 c# 源代码文本中。编译器总是将其解析为具体类型。如果你有方法

    void Test<T>(T arg)
    {
    }
    

    这样称呼它

    Test("hello");
    Test(3);
    

    编译器为两种方法生成代码!

    void Test(string arg)
    {
    }
    
    void Test(int arg)
    {
    }
    

    这意味着如果你想要一个可调用的方法,你必须为你的泛型参数提供具体的类型。

    【讨论】:

      【解决方案4】:

      此代码将为您提供所需类型的Expression&lt;Func&lt;&gt;&gt;。请注意,有一个 Expression.Lambda(...) 覆盖不需要您指定返回的 Func 的类型。

          var t = typeof(Foo);
          var pi = t.GetProperty(...);
          var prm = Expression.Parameter(t, t.Name);
          var prx = Expression.Property(prm, pi);
          var lambda = Expression.Lambda(prx, prm);
      

      请注意,在许多情况下,您不必费心以这种方式创建Expression&lt;Func&lt;&gt;&gt;,假设下面的structureConfigurationStructureConfiguration&lt;Foo&gt;,类型推断将允许您编写如下内容:

          structureConfiguration.Ignore(f => f.Bar);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-07-06
        • 1970-01-01
        • 2021-03-17
        • 1970-01-01
        • 2011-09-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多