我一直在我的代码中运行相同模式的需求,这经常需要验证对象中所有属性的值。伪代码如下所示:
bool ValidateMe(object c) {
var properties = GetProperties(c);
foreach (var property in properties) {
var value = property.GetValue(c);
if (!IsValid(value)) {
return false;
}
}
return true;
}
bool IsValid(int value)
{
return value != int.MaxValue;
}
bool IsValid(double value)
{
return value != double.MaxValue;
}
bool IsValid(object value)
{
return value != null;
} // etc.
我希望代码根据对象的类型动态地将值分配给正确的方法(可以通过调用property.PropertType
或value.GetType()
来找到,假设值不为null)。
我发现做这项工作的唯一方法是这样的:
interface IValidator {
bool IsValid(object value);
}
class PredicateValidator<T> : IValidator {
private Predicate<T> method;
PredicateValidator(Predicate<T> method) {
this.method = method;
}
bool IsValid(object value) {
return IsValid((T) value);
}
bool IsValid(T value) {
return method.invoke(value);
}
}
var validationsByType = new Dictionary<Type,IValidator>();
validationsByType[typeof(double)]=new PredicateValidator<double>(IsValid);
validationsByType[typeof(double)]=new PredicateValidator<int>(IsValid);
然后Map允许按类型调度对象以更正方法:
object value = property.GetValue(c);
bool result = validationsByType[c.GetType()].IsValid(value);
在运行时通过Type执行此动态调度是否有本机C#(即语言功能)?
答案 0 :(得分:1)
如果您想保持“名义反思执行”,那么您的方法很好。 我的建议是避免反射为“正常”执行代码。
它需要使用极其抽象的对象(通常是System.Object)。 您总是可以使用泛型和/或反射在“fire / init time”上生成一个适合您需要的委托,而不需要“非执行”中的任何类型解析,并自然地使用委托。
一个简短的例子来说明它
static public Validation
{
//Simply call the delegate (generic method is easier to use than generic class)
static public bool Validate<T>(T value)
{
return Validation<T>.Validate(value);
}
}
委托的实施
static public Validation<T>
{
static public readony Fun<T, bool> Validate;
static Validation
{
if (typeof(T) == typeof(string))
{
Validation<T>.Validate = new Func<T, bool>(value =>
{
var _string = (string)(object)value;
//Do your test here
return true;
});
}
else if (typeof(T) == typeof(int))
{
Validation<T>.Validate = new Func<T, bool>(value =>
{
var _int32 = (int)(object)value;
//Do your test here
return true;
});
}
//...
else if (typeof(T).IsClass)
{
var validate = typeof(Validation).GetMethod("Validate");
var parameter = Expression.Parameter(typeof(T));
var properties = typeof(T).GetProperties();
if (properties.length < 0)
{
Validation<T>.Validate = new Func<T, bool>(value => true);
}
else
{
var body = Expression.Constant(true);
foreach (var property in properties)
{
body = Expression.Condition(Expression.Call(validate.MakeGenericMethod(property.PropertyType), parameter), body, Expression.Constant(false));
}
Validation<T>.Validate = Expression.Lambda<Func<T, bool>>(body, parameter).Compile();
}
}
}
}
答案 1 :(得分:1)
dynamic
关键字将正确执行downcast。因此,上面的代码更改将更改为:
bool ValidateMe(object c) {
var properties = GetProperties(c);
foreach (var property in properties) {
var value = property.GetValue(c);
if (!IsValid((dynamic) value)) {
return false;
}
}
return true;
}
bool IsValid(int value)
{
return value != int.MaxValue;
}
bool IsValid(double value)
{
return value != double.MaxValue;
}
然后,.NET Runtime将搜索要调用的最具体的方法签名。我之前认为dynamic
仅适用于Duck Typing,但它也可用于动态调度重载方法。