动态Linq-对具有“”类型成员的对象执行查询;“动态”;

本文关键字:动态 对象 执行 查询 Linq- 成员 类型 | 更新日期: 2023-09-27 18:20:07

我正在尝试使用动态linq查询来检索IEnumerable<T>从一个对象集合(从Linq到object),集合中的每个对象都有一个内部集合和另一组存储数据的对象,这些值是通过外部集合的索引器访问的

当您使用强类型对象时,动态linq查询会按预期返回过滤集,但我的对象将数据存储在dynamic类型的成员中,请参阅下面的示例:

public class Data
{
    public Data(string name, dynamic value)
    {
        this.Name = name;
        this.Value = value;
    }
    public string Name { get; set; }
    public dynamic Value { get; set; }
}
public class DataItem : IEnumerable
{
    private List<Data> _collection;
    public DataItem()
    { _collection = new List<Data>(); }
    public dynamic this[string name]
    {
        get
        {
            Data d;
            if ((d = _collection.FirstOrDefault(i => i.Name == name)) == null)
                return (null);
            return (d.Value);
        }
    }
    public void Add(Data data)
    { _collection.Add(data); }
    public IEnumerator GetEnumerator()
    {
        return _collection.GetEnumerator();
    }
}
public class Program
{
    public void Example()
    {
        List<DataItem> repository = new List<DataItem>(){
            new DataItem() {
                new Data("Name", "Mike"),
                new Data("Age", 25),
                new Data("BirthDate", new DateTime(1987, 1, 5))
            },
            new DataItem() {
                new Data("Name", "Steve"),
                new Data("Age", 30),
                new Data("BirthDate", new DateTime(1982, 1, 10))
            }
        };
        IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("it['"Age'"] == 30");
        if (result.Count() == 1)
            Console.WriteLine(result.Single()["Name"]);
    }

当我运行上面的示例时,我得到:运算符'=='与操作数类型'Object'和'Int32'不兼容

动态成员是否与动态Linq查询不兼容?,或者,在处理动态类型的成员时,是否有另一种构建表达式的方法可以正确评估

非常感谢你的帮助。

动态Linq-对具有“”类型成员的对象执行查询;“动态”;

动态成员是否与动态Linq查询不兼容?,或者,在处理dynamic类型的成员时,是否有其他方法可以构造正确求值的表达式?

两者可以协同工作。在进行比较之前,只需转换为Int32即可:

IEnumerable<DataItem> result = 
           repository.AsQueryable<DataItem>().Where("Int32(it['"Age'"]) == 30");

编辑1:话虽如此,由于表达式树中不允许进行动态操作,因此通常会限制与Linq结合使用动态绑定。考虑以下Linq-To对象查询:

IEnumerable<DataItem> result = repository.AsQueryable().
                                                  Where(d => d["Age"] == 30);

由于上述原因,此代码段不会编译。

编辑2:在您的情况下(以及与Dynamic Linq一起),有一些方法可以绕过编辑1和原始问题中提到的问题。例如:

// Variant 1: Using strings all the way
public void DynamicQueryExample(string property, dynamic val)
{
   List<DataItem> repository = new List<DataItem>(){
        new DataItem() {
            new Data("Name", "Mike"),
            new Data("Age", 25),
            new Data("BirthDate", new DateTime(1987, 1, 5))
        },
        new DataItem() {
            new Data("Name", "Steve"),
            new Data("Age", 30),
            new Data("BirthDate", new DateTime(1982, 1, 10))
        }
    };
    // Use string comparison all the time        
    string predicate = "it['"{0}'"].ToString() == '"{1}'"";
    predicate = String.Format(whereClause , property, val.ToString());
    var result = repository.AsQueryable<DataItem>().Where(predicate);
    if (result.Count() == 1)
        Console.WriteLine(result.Single()["Name"]);
}
Program p = new Program();
p.DynamicQueryExample("Age", 30); // Prints "Steve"
p.DynamicQueryExample("BirthDate", new DateTime(1982, 1, 10)); // Prints "Steve"
p.DynamicQueryExample("Name", "Mike"); // Prints "Steve" (nah, just joking...)

或:

// Variant 2: Detecting the type at runtime.
public void DynamicQueryExample(string property, string val)
{
    List<DataItem> repository = new List<DataItem>(){
        new DataItem() {
            new Data("Name", "Mike"),
            new Data("Age", 25),
            new Data("BirthDate", new DateTime(1987, 1, 5))
        },
        new DataItem() {
            new Data("Name", "Steve"),
            new Data("Age", 30),
            new Data("BirthDate", new DateTime(1982, 1, 10))
        }
    };
    string whereClause = "{0}(it['"{1}'"]) == {2}";

    // Discover the type at runtime (and convert accordingly)
    Type type = repository.First()[property].GetType();
    string stype = type.ToString();
    stype = stype.Substring(stype.LastIndexOf('.') + 1);
    if (type.Equals(typeof(string))) {
        // Need to surround formatting directive with ""
        whereClause = whereClause.Replace("{2}", "'"{2}'"");
    }
    string predicate = String.Format(whereClause, stype, property, val);
    var result = repository.AsQueryable<DataItem>().Where(predicate);
    if (result.Count() == 1)
        Console.WriteLine(result.Single()["Name"]);
}
var p = new Program();
p.DynamicQueryExample("Age", "30");
p.DynamicQueryExample("BirthDate", "DateTime(1982, 1, 10)");
p.DynamicQueryExample("Name", "Mike");

下面的代码对您有用吗?

IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("it['"Age'"].ToString() == '"30'"");

但要实现这一点,可以分配给Data类的Value成员的所有类型都需要有ToString方法的有用实现。

您尝试过it['"Age'"].Equals(object(30))吗?

这样:

IEnumerable<DataItem> result = 
    repository.AsQueryable<DataItem>().Where("it['"Age'"].Equals(object(30))");

编辑:更新为将30正确投射到对象。