同一列表中的多个泛型类型并调用它们的方法
问题描述:
我在业余时间制作一个对象验证框架来学习一些东西,并可能将它用于一些学校项目。同一列表中的多个泛型类型并调用它们的方法
我有我的通用规则类,它看起来是这样的:
class Rule<T>
{
string propertyName;
Func<T, bool> ruleLambda;
bool IsBroken(T value)
{
return ruleLambda(value);
}
}
将被验证看起来有点像这样的对象:
class Example
{
List<Rule<?>> MyRules; // can take all types of rules
List<Rule<T>> Validate<T>(string propertyName, T value)
{
List<Rule<T>> brokenRules = new List<Rule<T>>();
foreach (Rule rule in MyRules.Where(r => r.propertyName == propertyName))
{
if (rule.IsBroken(value))
brokenRules.Add(rule);
}
return brokenRules;
}
}
凡T value
论证会其中一个Example类的属性值,可以是任何类型的值。
只要设置了属性,就会调用Validate<T>
方法。
问题在于班级的规则列表。具体是上面的List<Rule<?>>
行。我想将给定类的所有规则存储在同一个列表中。
唉,C#没有像Java一样的泛型类型的通配符。
我该怎么做?
使用对象而不是T的非泛型接口或基类可以工作,但我该如何调用泛型规则的IsBroken
方法而不是非泛型方法?
答
我已经尝试了一些东西,我发现一些作品非常好满足我的需求。我有一个抽象基规则类Rule<T>
继承,与通用IsBroken
方法:
abstract class Rule
{
string propertyName;
Func<object, bool> objectRule;
bool IsBroken<T>(T value)
{
Rule<T> rule = this as Rule<T>;
if (rule == null)
return objectRule(value);
return rule.IsBroken(value);
}
}
正如你所看到的,我尝试使用泛型类型参数在IsBroken
方法对基类转换为它的通用同行。
此外,在创建一个Rule<T>
实例时,我送一个Func<object, bool>
其基类的受保护的构造:
public Rule(string propertyName, Func<T, bool> ruleLambda)
: base(propertyName, ConvertToObjectFunc(ruleLambda))
{
}
与转换方法看起来像这样:
static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func)
{
return new Func<object, bool>(o => func((T)o));
}
但是,如果它能够不会把o改成T型,它会崩溃。所以我写了这个......东西:
static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func)
{
return new Func<object, bool>
(
o =>
{
try
{
T obj = (T)o;
return func(obj);
}
catch { return true; } // rule is broken by default
}
);
}
这是非常丑陋的,但它的作品。希望这可以帮助其他人。
答
在我需要类似这样的情况下,我使用接口或非泛型基类。例如,你可以创建一个接口:
public interface IRule
{
//non-generic properties & methods
}
public class Rule<T> : IRule
{
//implementation
}
然后创建接口的列表:
private List<IRule> MyRules;
如果你想从接口转换成通用的方便,你可以添加一个扩展方法:
public static Rule<T> ToGeneric<T>(this IRule rule)
{
return rule as Rule<T>;
}
答
我会存储您的规则object
的Example
类中,并使用Enumerable.OfType<T>
来找到一个给定的匹配规则类型:
class Example
{
private List<object> rules;
List<Rule<T>> Validate<T>(string propertyName, T value)
{
return this.rules.OfType<Rule<T>>()
.Where(r => r.PropertyName == propertyName && r.IsBroken(value))
.ToList();
}
}
定义一个接口IRule,带有非通用接口,例如'布尔IsBroken(物体)',并有'规则:IRule',并有'列表'..好吧,它不是很漂亮,但它*工作,是我见过的最好的。 –
2012-08-25 20:34:55