你一个更好的设计是为您的规则应用测试本身(或为任意值)
通过与Func键情况下这样做,你将获得最大的灵活性,像这样:
IEnumerable<Func<T,bool> tests; // defined somehow at runtime
foreach (var item in items)
{
foreach (var test in tests)
{
if (test(item))
{
//do work with item
}
}
}
那么你的具体测试会是这样的强类型检查在编译时:
public Func<T,bool> FooEqualsX<T,V>(V x)
{
return t => EqualityComparer<V>.Default.Equals(t.Foo, x);
}
对于反射形式
public Func<T,bool> MakeTest<T,V>(string name, string op, V value)
{
Func<T,V> getter;
var f = typeof(T).GetField(name);
if (f != null)
{
if (!typeof(V).IsAssignableFrom(f.FieldType))
throw new ArgumentException(name +" incompatible with "+ typeof(V));
getter= x => (V)f.GetValue(x);
}
else
{
var p = typeof(T).GetProperty(name);
if (p == null)
throw new ArgumentException("No "+ name +" on "+ typeof(T));
if (!typeof(V).IsAssignableFrom(p.PropertyType))
throw new ArgumentException(name +" incompatible with "+ typeof(V));
getter= x => (V)p.GetValue(x, null);
}
switch (op)
{
case "==":
return t => EqualityComparer<V>.Default.Equals(getter(t), value);
case "!=":
return t => !EqualityComparer<V>.Default.Equals(getter(t), value);
case ">":
return t => Comparer<V>.Default.Compare(getter(t), value) > 0;
// fill in the banks as you need to
default:
throw new ArgumentException("unrecognised operator '"+ op +"'");
}
}
如果你想成为真正内省和处理任何文字不知道在编译时你可以使用CSharpCodeProvider编写一个函数假设是这样的:
public static bool Check(T t)
{
// your code inserted here
}
当然,这是一个巨大的所以任何可以提供代码的人都必须完全信任。这里是您的特定需求比较有限实现(没有理智可言检查)
private Func<T,bool> Make<T>(string name, string op, string value)
{
var foo = new Microsoft.CSharp.CSharpCodeProvider()
.CompileAssemblyFromSource(
new CompilerParameters(),
new[] { "public class Foo { public static bool Eval("+
typeof(T).FullName +" t) { return t."+
name +" "+ op +" "+ value
+"; } }" }).CompiledAssembly.GetType("Foo");
return t => (bool)foo.InvokeMember("Eval",
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod ,
null, null, new object[] { t });
}
// use like so:
var f = Make<string>("Length", ">", "2");
对于这个任意类型的工作,你就必须做一些更多的思考,找到目标物的安装类型参考它在编译器参数中。
private bool Eval(object item, string name, string op, string value)
{
var foo = new Microsoft.CSharp.CSharpCodeProvider()
.CompileAssemblyFromSource(
new CompilerParameters(),
new[] { "public class Foo { public static bool Eval("+
item.GetType().FullName +" t) "+
"{ return t."+ name +" "+ op +" "+ value +"; } }"
}).CompiledAssembly.GetType("Foo");
return (bool)foo.InvokeMember("Eval",
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod ,
null, null, new object[] { item });
}
所有上面的代码仅仅是一种概念证明,它缺乏健全检查,并有严重的性能问题。
如果你想成为更炫,你可以使用Reflection.Emit的DynamicMethod的用实例来做到这一点(使用正确的运营商,而不是默认的比较情况),但是这将需要类型的重载运营商复杂的操作。
通过使您的检查代码具有高度通用性,您可以在将来根据需要包含更多测试。从代码中提取这些函数,基本上隔离只关心函数的代码部分,而不是从t - > true/false。
然后一个代表解决方案似乎是非常接近你需要的;除非stringCode是真正动态的(用户提供的内容,即时)。然后,只要你的特定情况保持不变,你就可以通过DLR(这将在.NET 4.0中即将推出,我不知道有足够的帮助) – 2009-07-30 17:47:08
需要一些东西,那么你可以实现它。如果你需要能够执行*任意*逻辑而不是所描述的固定形式,那么你就会遇到问题。基本上,只要预先知道“代码”的所有输入的集合,并且除了返回单个值(再次在编译时已知类型(即使只是作为“对象”),也没有副作用)那么这是可能的,任何超出这个范围的东西,你都不在eval这样的东西之外 – ShuggyCoUk 2009-07-30 18:29:19