vendredi 2 décembre 2016

Dynamic dispatch by Type only known at runtime

I keep running across the need for the same pattern in my code, which frequently needs to validate the values of all the properties in an object. The pseudo code looks like this:

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.

I want the code to dynamically dispatch the value to the correct method based on the object's Type (which can be found by calling property.PropertType or value.GetType() assuming value is not null).

The only way I have found to make this work is something like this:

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

and then the Map enables dispatching the object to correct method by type:

object value = property.GetValue(c);
bool result = validationsByType[c.GetType()].IsValid(value);

So while this is working, I keep thinking there must be a more compact/better way of doing this.





Aucun commentaire:

Enregistrer un commentaire