5
\$\begingroup\$

The source code, or rather the concept I'd like to get reviewed is what now allows me to do the following during reflection:

object validator;  // An object known to implement IValidation<T>
object toValidate; // The object which can be validated by using the validator.

// Assume validator is IValidation<string> and toValidate string.

IValidation<object> validation
    = Proxy.CreateGenericInterfaceWrapper<IValidation<object>>( validator );

validation.IsValid( toValidate ); // This works! No need to know about the type.

// Assuming the validator validates strings, this will throw an InvalidCastException.
//validation.IsValid( 10 );

I no longer need to know about concrete types during reflection where I know types will match. It looks kind of like covariance but the result only works because types are guaranteed to match. This allows me to support any type, since no manual type checks need to be done to cast to the correct interface type.

The CreateGenericInterfaceWrapper method uses RunSharp to emit the code. This source code, and an extended explanation can be found on my blog.

My main concerns are:

  • Did anybody encounter such a use case before, and found a better way to solve it?
  • Did I write something which I could just have found in an existing library?

To further clarify why I wrote this solution, I copied the example from my blog of the code I would have to write to be able to use the IsValid method during reflection.

object validator;  // An object known to implement IValidation<T>
object toValidate; // The object which can be validated by using the validator.

// 'validator' can be any type validator which can validate 'toValidate'.

if ( validator is IValidation<string> )
{
    IValidation<string> validation = (IValidation<string>)validator;
    validation.IsValid( (string)toValidate );
}
else if ( validator is IValidation<int> )
{
    IValidation<int> validation = (IValidation<int>)validator;
    validation.IsValid( (int)toValidate );
}
else if ... // and so on to support any possible type ...
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Having check the articles on your blog, I still haven't found the actual (concrete) use cases (which you said exist). Could you elaborate a bit more on that? I don't see the point where you would switch to having an object as the type of your class instance (there are usually ways which keep the type safety around). Obviously, once you've lost the type information, generics are pretty useless, but the point is to keep this information around, not to break type safety in order to get back this information after it has been lost. \$\endgroup\$
    – vgru
    Jul 3, 2011 at 19:23
  • \$\begingroup\$ @Groo: I updated my question in an attempt to clarify the problem. Actually the posted code is a concrete example which I use in my library. The problem lies in the fact that validator can be a validator for any type. An attribute applied to a property defines a certain validator. A factory class extracts this validator from the class and uses it. In my concrete scenario this is a dependency property factory which greatly simplifies creating and maintaining DPs. \$\endgroup\$ Jul 3, 2011 at 22:02
  • \$\begingroup\$ In this unit test you can see a use case of the attributes. Compare it to normal dependency property usage. My factory approach has less duplication and doesn't rely on string literals. \$\endgroup\$ Jul 3, 2011 at 22:03
  • 2
    \$\begingroup\$ Ok, you could have just used a non-generic interface (e.g. IValidation.Valid(object)), although each concrete implementation would have to cast the object to the appropriate type (which is what the wrapper does right now for you). Your approach nevertheless gives stronger type safety while implementing individual validators. \$\endgroup\$
    – vgru
    Jul 5, 2011 at 8:30
  • \$\begingroup\$ @Groo: Yup! Nice insight, didn't look at it that way before. I love generics. ;p \$\endgroup\$ Jul 5, 2011 at 9:50

2 Answers 2

7
\$\begingroup\$

Did anybody encounter such a use case before, and found a better way to solve it?

There's the IEnumerable pattern:

public interface IValidation
{
    bool IsValid(object obj);
}

public interface IValidation<T> : IValidation
{
    bool IsValid(T t);
}

public abstract class BaseValidation<T> : IValidation<T>
{
    public bool IsValid(object obj)
    {
        return IsValid((T)obj);
    }

    public abstract bool IsValid(T t);
}

Whether it's better or not is debatable, but it should at least be familiar to anyone who has to maintain your code.

\$\endgroup\$
0
1
\$\begingroup\$

I recently faced a similar problem, but took a duck-typing approach instead, which works providing the type assumptions hold. For your case, this is what I would have written:

var validatorType = validator.GetType();
validatorType.GetMethod("IsValid").Invoke(validator, toValidate);

If there are overloads of IsValid, you'll need to specify the one with the right argument type in the call to GetMethod, but you can find that from toValidate.GetType().

\$\endgroup\$
8
  • 1
    \$\begingroup\$ Thanks for the answer, but I believe it's a less optimal solution. 1. Invoke is really slow. To this extent I previously posted how I create delegates from MethodInfo which are a lot faster than using Invoke. \$\endgroup\$ Jul 3, 2011 at 13:55
  • 1
    \$\begingroup\$ 2. You rely on string literals to find the methods, you'll have to manually find every method in the interface. My solution uses the interface itself to find the methods, so you can change the interface without having to rewrite other code. \$\endgroup\$ Jul 3, 2011 at 13:57
  • 1
    \$\begingroup\$ 3. Type safety is already broken, so the following isn't that much of an advantage. Still, you can choose to use any less generic type parameters, not only object. E.g. IValidation<IValidatable>. \$\endgroup\$ Jul 3, 2011 at 14:06
  • \$\begingroup\$ All fair points, but are you sure that using Invoke is slower than using Reflection.Emit? I presume that CreateGenericInterfaceWrapper is caching the work it does. In my case these choices were reasonable given the context. \$\endgroup\$
    – Rafe
    Jul 4, 2011 at 0:11
  • \$\begingroup\$ I'm pretty sure Reflection.Emit is slower, since it compiles classes at runtime. The thing is you only need to compile once, and then you'll have the same speed as an ordinary compiled class. Thus the only added overhead is an extra method call and the casts to the correct types. Jon's results say Invoke is 600 times as slow. Of course, if you don't need the speed, don't worry about it. ;p \$\endgroup\$ Jul 4, 2011 at 0:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.