代码之家  ›  专栏  ›  技术社区  ›  Kenneth Cochran

如何使用用户定义的条件查询对象集合?

  •  0
  • Kenneth Cochran  · 技术社区  · 15 年前

    抱歉,这有点抽象。我正处于发展的早期阶段。

    我有两种对象类型:

    1. 需要存储一系列用户定义条件的对象。
    2. 与第一个对象中定义的零个或多个条件相匹配的对象。

    下面是一个简单的例子,说明它将如何运行。

    1. 用户创建多个类型为2的对象,并将其添加到集合中。
    2. 然后,用户创建一个类型为1的对象,并为其指定多个条件。
    3. 系统使用对象类型1中的条件生成类型2的对象列表,按每个对象匹配的条件百分比排序。

    以下是预期输出的示例:

    Conditions                                            List
    Quantity >= 2                                         Object5 100%
    Value < 2                                             Object2  75%
    Category = "Blah"                                     Object4  50%
    Quality > 5                                           Object1  25%
                                                          Object3   0%
    

    每个条件中的第一个操作数是属性的名称,而第二个操作数是该属性的值。

    我怎样才能做到这一点?

    我的第一个想法是,它看起来类似于查询语言。如果它们是DB表中的记录,我可以为每个条件缝合一个SQL字符串,运行每个查询,并计算每个记录id在查询结果中出现的次数。但这些都是普通的旧C#对象。我还没有决定使用什么来实现对象持久性,所以我现在不想把自己绑定到db引擎上。有什么建议吗?

    4 回复  |  直到 15 年前
        1
  •  1
  •   Garett    15 年前

    这听起来像 LINQ 是您想要使用的。特别是,我会调查 LINQ To Objects 和 LINQ To SQL 如果最终选择了持久性存储。

        2
  •  0
  •   jebberwocky    15 年前

    还有一篇关于 how Directly Execute SQL Queries (LINQ to SQL)

    Northwnd db = new Northwnd(@"c:\northwnd.mdf");
    IEnumerable<Customer> results = db.ExecuteQuery<Customer>
    (@"SELECT c1.custid as CustomerID, c2.custName as ContactName
        FROM customer1 as c1, customer2 as c2
        WHERE c1.custid = c2.custid"
    );
    
        3
  •  0
  •   Jeff Mercado    15 年前

    下面是一个使用LINQ到字符串上的对象的示例实现:

    var conditions = new Func<string, bool>[]
    {
        s => s.Length < 4,                  // less than 4 characters
        s => s.Count(c => c == 'o') > 2,    // more than 2 'o's
        s => s == "fooo",                   // is "fooo"
        s => s.Contains('b'),               // contains 'b'
    };
    var words = new[] { "foo", "fooo", "foooo", "bar", "barr", "bazooo" };
    var query = words.Select(Word => new
                                     {
                                         Word,
                                         Percentage = conditions.Average(c => c(Word) ? 1M : 0M)
                                     })
                     .Where(p => p.Percentage > 0)          // keep words matches some conditions
                     .OrderByDescending(p => p.Percentage)  // order by the percentage
                     .ThenBy(p => p.Word);                  // then order in alphabetical order
    

    回想起来,我认为这个例子可能也适用于LINQ to SQL(在 conditions 数组)。

    这只是一个简单的例子,但你当然可以进一步扩展这个想法。

        4
  •  0
  •   Bryan Watts    15 年前

    您可以通过修改版本的 Specification pattern .从一个以百分比表示结果的界面开始:

    public interface ISpecification<T>
    {
        double GetPercentSatisfiedBy(T target);
    }
    

    接下来,创建一个应用任意条件的规范:

    public sealed class Specification<T> : ISpecification<T>
    {
        private readonly Func<T, bool> _predicate;
    
        public Specification(Func<T, bool> predicate)
        {
            _predicate = predicate;
        }
    
        public double GetPercentSatisfiedBy(T target)
        {
            return _predicate(target) ? 1 : 0;
        }
    }
    

    现在,创建一个线性组合其他规范结果的规范:

    public sealed class CompositeSpecification<T> : ISpecification<T>
    {
        private readonly IList<ISpecification<T>> _specifications;
    
        public CompositeSpecification(params ISpecification<T>[] specifications)
        {
            _specifications = specifications.ToList();
        }
    
        public double GetPercentSatisfiedBy(T target)
        {
            return _specifications.Average(
                specification => specification.GetPercentSatisfiedBy(target));
        }
    }
    

    最后,构建一个包含所有期望条件的规范,并将其应用于 Foo 物体:

    var specification = new CompositeSpecification<Foo>(
        new Specification<Foo>(foo => foo.Quantity >= 2),
        new Specification<Foo>(foo => foo.Value < 2),
        new Specification<Foo>(foo => foo.Category == "Blah"),
        new Specification<Foo>(foo => foo.Quality > 5));
    
    var foos = new List<Foo> { ... };
    
    var results =
        from foo in foos
        let percentSatisfied = specification.GetPercentSatisfiedBy(foo)
        orderby percentSatisfied descending
        select new
        {
            Foo = foo,
            PercentSatisfied = percentSatisfied
        };
    

    这种设计支持任意复杂度的规范。

    推荐文章