C# 如何使用用户定义的条件查询对象集合?
抱歉,这有点抽象。我正处于发展的早期阶段 我有两种对象类型: 需要存储一系列用户定义条件的对象。 与第一个对象中定义的零个或多个条件相匹配的对象。 下面是一个简单的示例,说明它将如何运行 用户创建多个类型为2的对象并将其添加到集合中。 然后,用户创建类型为1的对象,并为其指定若干条件。 系统使用对象类型1中的条件生成类型2的对象列表,按每个对象匹配的条件百分比排序。 以下是预期输出的示例:C# 如何使用用户定义的条件查询对象集合?,c#,collections,conditional-statements,user-defined,C#,Collections,Conditional Statements,User Defined,抱歉,这有点抽象。我正处于发展的早期阶段 我有两种对象类型: 需要存储一系列用户定义条件的对象。 与第一个对象中定义的零个或多个条件相匹配的对象。 下面是一个简单的示例,说明它将如何运行 用户创建多个类型为2的对象并将其添加到集合中。 然后,用户创建类型为1的对象,并为其指定若干条件。 系统使用对象类型1中的条件生成类型2的对象列表,按每个对象匹配的条件百分比排序。 以下是预期输出的示例: Conditions
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引擎上。有什么建议吗?这听起来像是你想要使用的。特别是,我将研究是否最终选择了持久性存储
下面是使用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
回想起来,我认为这个例子可能也适用于LINQtoSQL,并对conditions数组进行了一些调整
这只是一个简单的例子,但您当然可以进一步扩展这个想法。您可以通过修改版本的。从一个将结果表示为百分比的界面开始:
public interface ISpecification<T>
{
double GetPercentSatisfiedBy(T target);
}
此设计支持任意复杂度的规范
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));
}
}
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
};