动态linq中的调用函数

时间:2013-08-19 12:03:57

标签: c# linq linq-to-objects dynamic-linq

我正在尝试在动态linq select语句中调用一个函数,但是我得到了错误:

No property or field 'A' exists in type 'Tuple2'

示例代码:

void Main()
{
    var a = new Tuple<int, int>(1,1);
    var b = new[]{ a };
    var q = b.AsQueryable().Select("A.Test(it.Item1)");

    q.Dump();
}

public static class A
{
    public static int Test(int i)
    {
        return i++;
    }
}

我应该如何更改代码才能使其正常工作?

如果我调用内置函数Convert.ToInt32,它可以正常工作。

var q = b.AsQueryable().Select("Convert.ToInt32(it.Item1)");

另外如何使用动态linq投射属性?

var q = b.AsQueryable().Select("((float)it.Item1)");

7 个答案:

答案 0 :(得分:10)

我会说dynamic-linq不够“强大”来做这些事情。它仅在给定对象和一些特殊类中查找方法:MathConvert,各种基类型(intfloatstring ,. ..),GuidTimespanDateTime

如果在文件上使用ilspy / reflector,则可清楚地看到这些类型的列表。他们在System.Linq.Dynamic.ExpressionParser.predefinedTypes

现在,显然我可能错了,但这有效:.Select("Guid.NewGuid().ToString()").Cast<string>().ToArray()

显示这很可能是“正确”列表。

如果您有兴趣http://www.krizzcode.com/2012/01/extending-dynamiclinq-language.html

,这里有一篇关于如何修改动态LINQ的文章

现在,一个聪明的人将采用动态linq的源头并简单地扩展该阵列...但是这里没有聪明的人......只有程序员需要 blood Blood 但尤其是内脏

var type = typeof(DynamicQueryable).Assembly.GetType("System.Linq.Dynamic.ExpressionParser");

FieldInfo field = type.GetField("predefinedTypes", BindingFlags.Static | BindingFlags.NonPublic);

Type[] predefinedTypes = (Type[])field.GetValue(null);

Array.Resize(ref predefinedTypes, predefinedTypes.Length + 1);
predefinedTypes[predefinedTypes.Length - 1] = typeof(A); // Your type

field.SetValue(null, predefinedTypes);

在第一次调用Dynamic Linq之前执行此操作(使用所需的类型)(因为在第一次调用之后,这些类型的方法/属性被缓存)

说明:我们使用反射将我们的对象添加到这个“特殊列表”。

答案 1 :(得分:6)

我知道已经有一个已接受的答案,但它对我不起作用。我正在使用Dynamic Linq 1.1.4。我想做这样的查询

$.GetNewestRisk() == null

其中GetNewestRisk()是$表示的对象上的公共方法。我一直收到此错误“运行查询时出错,无法访问类型'患者'上的方法(在索引2处)”。

我在源代码中发现有一个GlobalConfig对象,它允许分配一个自定义提供程序,它将包含您可能想要使用的所有类型。以下是自定义提供程序的源代码:

public class CustomTypeProvider: IDynamicLinkCustomTypeProvider
{
    public HashSet<Type> GetCustomTypes()
    {
        HashSet<Type> types = new HashSet<Type>();
        types.Add(typeof(Patient));
        types.Add(typeof(RiskFactorResult));
        types.Add(typeof(PatientLabResult));
        types.Add(typeof(PatientVital));
        return types;
    }
}

以下是我使用它的方式:

System.Linq.Dynamic.GlobalConfig.CustomTypeProvider = new CustomType();

进行此调用后,我可以在表达式内的对象上调用方法。

答案 2 :(得分:2)

@xanatos回答并不适用于.Net Core版本。所以我在图书馆作者本人写的System.Dynamic.Linq.Core测试DynamicExpressionParserTests上找到了@Kent类似的相关内容。

给定的TestCustomTypeProvider类允许您使用DynamicLinqType类注释,这对此问题非常有用。

要回答问题,您只需要定义类(确保使用DynamicLinqType进行注释):

[DynamicLinqType] 
public static class A
{
   public static int Test(int i)
   {
      return i++;
   }
}

如上所述添加customTypeProvider:

private class TestCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
{
   private HashSet<Type> _customTypes;

   public virtual HashSet<Type> GetCustomTypes()
   {
      if (_customTypes != null)
      {
          return _customTypes;
      }

      _customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly }));
            return _customTypes;
    }
}

并使用带the configurable Select的ParsingConfig来调用它:

var config = new ParsingConfig
{
     CustomTypeProvider = new TestCustomTypeProvider()
};

var q = b.AsQueryable().Select(config, "A.Test(it.Item1)");

答案 3 :(得分:0)

var b = new[]{ a };

上面的数组不知道什么类型的数组,并且它不是类型安全的?

您的值是以变量数据类型分配的,因此它不是整数值(我认为字符串值),当您在查询中获取此值时,必须转换为.toint32(),因为您的类参数数据类型为整数

请尝试

 var b = new **int**[]{ a }; 

而不是var b = new[]{ a };

重要提示在这里(粗体):

No property or field 'xxx' exists in **type** 'xxx'

请查看以前的讨论:

Dynamic Linq - no property or field exists in type 'datarow'

答案 4 :(得分:0)

我可能会感到困惑,但是你在Select s中使用字符串的语法不能为我编译。以下语法有效:

var q = b.AsQueryable().Select(it => A.Test(it.Item1));

答案 5 :(得分:0)

以下适用于我:

var a = new Tuple<int, int>(1, 1);
var b = new[] { a };
var q = b.AsQueryable().Select(it=>A.Test(it.Item1));
var q1 = b.AsQueryable().Select(it => Convert.ToInt32(it.Item1));
var q2 = b.AsQueryable().Select(it => (float) it.Item1);

答案 6 :(得分:0)

@Armand为该问题提供了一个出色的解决方案,作为我能够找到的唯一解决方案,我想为尝试相同方法的任何人添加到该解决方案中。

标有...的班级

[DynamicLinqType] 
在运行以下行时,必须考虑

...:

FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly })

在上面提供的解决方案中,这假定包含要评估的功能的类位于当前代码所在的同一类上。如果要在所述类之外使用这些方法,则程序集将需要更改。

FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { typeof(AnotherClassName).Assembly })

上面的解决方案没有任何变化,这只是为了澄清尝试使用它的任何人。