【问题标题】:Dynamic Projection using DynamicExpressionParser ParseLambda使用 DynamicExpressionParser ParseLambda 的动态投影
【发布时间】:2019-06-17 20:22:19
【问题描述】:

我正在尝试将一些创建动态投影的代码从 .Net 4.5 转换为 .Net Core 3;我在 .Net 4.5 中有以下代码

var e = DynamicExpression.ParseLambda(
                typeof(MyModel),
                typeof (object),
                "new(Id as id)");

ParseLambda 在 .Net Core 3 中的 DynamicExpression 上不可用,所以我将代码更改为:

var e = DynamicExpressionParser.ParseLambda(
            typeof(MyModel),
            typeof (object),
            "new(Id as id)");

但这会导致空引用异常,并带有以下堆栈跟踪

   at System.Linq.Dynamic.Core.Parser.ExpressionParser.CreateNewExpression(List`1 properties, List`1 expressions, Type newType)
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseNew()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseIdentifier()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParsePrimary()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseUnary()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseMultiplicative()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAdditive()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseShiftOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseComparisonOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseLogicalAndOrOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseIn()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAndOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseOrOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseLambdaOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseNullCoalescingOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseConditionalOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.Parse(Type resultType, Boolean createParameterCtor)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(ParsingConfig parsingConfig, Boolean createParameterCtor, ParameterExpression[] parameters, Type resultType, String expression, Object[] values)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(Boolean createParameterCtor, Type itType, Type resultType, String expression, Object[] values)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(Type itType, Type resultType, String expression, Object[] values)

当表达式为“Id == 0”或任何其他比较时,代码工作正常,但我无法让“新”表达式工作......

【问题讨论】:

    标签: c# linq asp.net-core projection


    【解决方案1】:

    传递 typeof(object) 作为结果类型适用于 ParseLambda 的 .Net 4.5 实现,但在查看 System.Linq.Dynamic.Core 源代码后,我发现 ParseLambda 可以采用 null 结果类型。以下代码在 .Net Core 3 中按预期工作。

    var e = DynamicExpressionParser.ParseLambda(
              typeof(MyModel),  // itType
              null,             // resultType
              "new(Id as id)"); // expression
    

    https://github.com/StefH/System.Linq.Dynamic.Core/blob/master/src/Microsoft.EntityFrameworkCore.DynamicLinq/EFDynamicQueryableExtensions.cs

    【讨论】:

      【解决方案2】:

      听起来您正在使用System.Linq.Dynamic.Core

      如果是这种情况,您需要确保输出类型的属性为id。您的代码不起作用,因为您的输出类型是 object 。由于 object 没有获得 id 属性,它会失败。

      由于类似的原因,您还需要确保输入类型获得Id的属性

      诀窍始终是使用一致的属性。例如,假设您有两种类型:

      public class MyInput                  // input 
      {
          public int Id { get; set; }
      }
      
      public class MyOutput                // output
      {
          public int id { get; set; }
      }
      

      你可以像下面这样解析一个字符串:

      var e = DynamicExpressionParser.ParseLambda(
          typeof(MyInput),                 // input type
          typeof(MyOutput),                // output type
          "new (Id as id)");               // initialize properties
      
      // test
      MyOutput o = e.Compile().DynamicInvoke(new MyInput() { Id = 123 }) as MyOutput;
      Console.WriteLine(o.id);     // outputs 123
      

      【讨论】:

      • 输出类型将取决于表达式中的属性,它可以像“new(Id as id)”一样简单,但它可能会更复杂,例如“new(Id as id, Company.Name as companyName, ...)" 为什么不能像 .Net 4.5 中那样简单地成为对象类型?
      • @Failwyn 您也可以在 .NET Core 中执行此操作。请试一试。顺便说一句,这与复杂性无关,而与类型安全有关。
      • 适用于 .Net 4 的确切代码在 .Net Core 中不起作用,我试图找出原因;投影的输出类型应该是什么?在Linq做投影的时候,没有具体的输出类型,如果不能是object,应该是什么?
      • @Failwyn 根据我的测试,上面的代码在.NET Framework.NET Core 上都有效。您是否认真对待没有具体的输出类型?那里总会有一个类型,至少是一个匿名类型。如果你想创建一个“动态”,请尝试ExpandoObject——我还没有测试过,但我想它应该可以按你的预期工作。
      • @Failwyn 很高兴听到您自己解决了这个问题。没有冒犯。如果我蹩脚的英语让你认为我在试图“妥协”,我很抱歉。我从来没有想过这样做。我还测试了ExpandoObject,正如你所说,它确实抛出了一个空引用异常。您使用null 作为参数的答案对我来说很好。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2014-07-21
      相关资源
      最近更新 更多