2010-10-28 3 views
0

Извините, если это немного абстрактно. Я нахожусь на ранних стадиях развития.Как запросить коллекцию объектов, используя пользовательские условия?

У меня есть два типа объектов:

  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% 

Первый операнд в каждом состоянии это имя свойства, в то время как второй операнд является значением этого свойства.

Как это сделать?

Моя первая мысль заключается в том, что она похожа на язык запросов. Если они были записями в таблице БД, я мог бы сшить строку SQL для каждого условия, запустить каждый запрос и подсчитать количество раз, когда каждый идентификатор записи появился в результатах запроса. Но это простые старые объекты C#. Я не решил, что использовать для сохранения объектов, но поэтому я бы не стал привязываться к движку db на этом этапе. Какие-либо предложения?

ответ

1

Это звучит так: LINQ - это то, что вы хотите использовать. В частности, я бы рассмотрел LINQ To Objects и LINQ To SQL, если в конечном итоге выбран магазин сохранения.

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

Вот пример реализация с помощью 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).

Это был просто быстрый пример, но вы можете еще больше расширить идею.

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 
    }; 

Эта конструкция поддерживает спецификации произвольной сложности.

Смежные вопросы