linq 动态链接中的调用函数

js81xvg6  于 2022-12-06  发布在  其他
关注(0)|答案(8)|浏览(127)

我尝试在动态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)");

另外,我如何使用动态链接转换属性?

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

cig3rfwq1#

以下内容对我很有效:

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);
0ejtzxu1

0ejtzxu12#

我要说的是,dynamic-linq并不“足够强大”,它只在给定的对象和一些特殊的类中寻找方法:MathConvert、各种基本类型(intfloatstring...)、GuidTimespanDateTime
如果你在文件上使用ilspy/reflector,这些类型的列表是清晰可见的。它们在System.Linq.Dynamic.ExpressionParser.predefinedTypes中。
很明显我可能错了,但这是可行的:.Select("Guid.NewGuid().ToString()").Cast<string>().ToArray()
表明这很可能是“正确”的列表。
如果您感兴趣,这里有一篇关于如何修改动态LINQ的文章http://www.krizzcode.com/2012/01/extending-dynamiclinq-language.html
现在,一个聪明的人会把动态链接的来源和简单地扩大数组...但这里没有聪明的人...只有程序员想要 * 血 血 *,特别是**内脏 *!

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之前执行此操作(使用所需的类型)(因为在第一次调用之后,这些类型的方法/属性将被缓存)
说明:我们使用反射将对象添加到这个“特殊列表”中。

ojsjcaue

ojsjcaue3#

我知道在这个问题上已经有一个公认的答案,但它对我不起作用。我使用的是Dynamic Linq 1.1.4。我想做这样的查询

$.GetNewestRisk() == null

其中GetNewestRisk()是由$表示的对象上的公共方法。我一直收到此错误“运行查询时出错,类型'Patient'上的方法不可访问(在索引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();

在进行这个调用之后,我就可以调用表达式中对象的方法了。

pn9klfpd

pn9klfpd4#

@xanatos的答案对.Net Core版本不起作用.所以我在System.Dynamic.Linq.Core上找到了一些类似的相关的由@肯特的作者自己编写的测试库DynamicExpressionParserTests。
给定的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;
    }
}

并使用带有可配置Select的ParsingConfig来调用它:

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

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

t0ybt7op5#

@阿曼德已经为这个问题提出了一个很好的解决方案,作为我唯一能找到的解决方案,我想为任何尝试同样方法的人补充一下。
标记为的类...

[DynamicLinqType]

...在运行以下行时必须考虑:

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

在上面提供的解决方案中,这假定包含要计算的函数的类与代码当前所在的类位于同一个类上。如果要在所述类之外使用方法,则需要更改程序集。

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

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

gajydyqb

gajydyqb6#

至于Dynamic LINQ的当前版本 (1.2.19),您可能会遇到另一个异常:

System.Linq.Dynamic.Core.Exceptions.ParseException : Enum value 'Test' is not defined in enum type 'A'

要让DLINQ知道您的类型'A',您有两个选项:
1.使用您自己的自定义类型提供程序设置分析配置,您可以在其中直接指定类型“A”。
1.使用属性 [DynamicLinqType] 标记类型。如果该类型加载到当前域中(这是通常的情况),您不必再做任何事情,因为默认的自定义类型提供程序已经在当前AppDomain中扫描了标记为 [DynamicLinqType] 的类型。您必须执行类似于answer操作。
如果您想同时使用两种方法-第一种用于类型'A',第二种用于类型'B',该怎么办?在这种情况下,您只需将类型'A'与默认提供程序类型“合并”即可:

public class DynamicLinqTests
{
    [Test]
    public void Test()
    {
        var a = new Tuple<int, int>(1, 1);
        var b = new[] { a };

        var parsingConfig = new ParsingConfig
        {
            ResolveTypesBySimpleName = true,
            CustomTypeProvider = new TestCustomTypesProvider()
        };

        var queryWithA = b.AsQueryable().Select(parsingConfig, "A.Test(it.Item1)");
        queryWithA.ToDynamicList();

        var queryWithB = b.AsQueryable().Select(parsingConfig, "B.Test(it.Item1)");
        queryWithB.ToDynamicList();
    }

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

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

    public class TestCustomTypesProvider : DefaultDynamicLinqCustomTypeProvider
    {
        public override HashSet<Type> GetCustomTypes()
        {
            var customTypes = base.GetCustomTypes();
            customTypes.Add(typeof(A));
            return customTypes;
        }
    }
}
blmhpbnm

blmhpbnm7#

我可能会感到困惑,但是您在Select s中使用字符串的语法对我来说无法编译。下面的语法有效:

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

06odsfpq8#

var b = new[]{ a };

上面的数组是不知道什么类型的数组,而且不是类型安全的?
你的值是以变量数据类型赋值的,所以它不是整数值(我认为是字符串值),当你在查询中得到这个值时,必须需要convert.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'

相关问题