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

时间:2010-10-28 04:20:28

标签: c# collections conditional-statements user-defined

对不起,如果这有点抽象。我现在处于发展的早期阶段。

我有两种对象类型:

  1. 需要存储一系列用户定义条件的对象。
  2. 匹配第一个对象中定义的零个或多个条件的对象。
  3. 以下是一个如何运行的简单示例。

    1. 用户创建多个类型为2的对象,并将它们添加到集合中。
    2. 然后,用户创建一个类型为1的对象,并为其指定几个条件。
    3. 系统使用对象类型1中的条件生成类型2的对象列表,按每个对象匹配的条件百分比排序。
    4. 以下是预期输出的示例:

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

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

      我该如何做到这一点?

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

4 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

另外,还有一篇关于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"
);

答案 2 :(得分:0)

以下是在字符串上使用LINQ-to-Objects的示例实现:

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数组进行一些调整)。

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

答案 3 :(得分:0)

您可以使用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
    };

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