Attribute metabehavior

Attributes in .NET can be used to add metadata to language elements. In combination with reflection they can be put to use in plenty of powerful scenarios. A separate parser can process the data added and act upon the annotations in any way desired. A common example of this is a serializer which knows how to serialize an instance of a class based on attributes applied to its members. E.g. a NonSerialized attribute determines the member doesn’t need to be serialized.

In my previous post I promised I would show some interesting scenarios where the mandatory enum values in my solution, needed to identify different dependency properties (DPs), can be put to good use. It is not required to grasp the entire subject previously discussed, but it does help to know about DPs and their capabilities. Simply put, they are special properties (used by XAML) which can notify whenever they are changed, allowing to bind other data to them. They can also be validated (check whether a value assigned to them is valid or not) and coerced (adjusting the value so it satisfies a certain condition). I consider these capabilities to be metadata, describing particular behavior associated with a given property. After extensive tinkering I found a way to express this behavior in an attribute, but it wasn’t easy. Ordinarily WPF requires you to pass callback methods along when ‘registering’ the DPs, which implement the desired behavior.

Two solutions can be considered:

  1. The parser knows how to interpret the metadata and acts accordingly.
  2. The attribute implements the actual behavior itself, and is simply called by the parser.

Solution 1 is the easiest to implement, and is how attributes are used most often. Solution 2 however has a great added benefit. It allows you to apply the strategy pattern. Unlike solution 1, the parser doesn’t need to know about the specific implementation, but only the interface. Additional behaviors can be implemented and used without having to modify the parser. In contrast to simple metadata, an actual behavior is attached, hence I am dubbing this metabehavior. I will discuss the loopholes you have to jump through to achieve this in a next post. For now, consider the following examples to see how it could be used.

A regular expression validation of a dependency property can be used as follows:

[DependencyProperty( Property.RegexValidation, DefaultValue = "test" )]
[RegexValidation( "test" )]
public string RegexValidation { get; set; }

Coercing a value within a certain range, defined by two other properties can be used as follows:

[DependencyProperty( Property.StartRange, DefaultValue = 0 )]
public int StartRange { get; set; }

[DependencyProperty( Property.EndRange, DefaultValue = 100 )]
public int EndRange { get; set; }

[DependencyProperty( Property.CurrentValue )]
[RangeCoercion( typeof( int ), Property.StartRange, Property.EndRange )]
public int CurrentValue { get; set; }

The greatest thing about all this, is that new behaviors can be implemented by extending from ValidationHandlerAttribute and CoercionHandlerAttribute respectively, albeit with some added complexities due to the limitations of attributes which I will discuss later.

Casting to less generic types

… because yes, there are valid use cases for it! Finally I found the time to write some unit tests, followed by fixing the remaining bugs, and am now excited to report on the result which effectively allows you to break type safety for generic interfaces, if you so please. Previously I discussed the variance limitations for generics, and how to create delegates which overcome those limitations. Along the same lines I will now demonstrate how to overcome those limitations for entire generic interfaces.

Consider the following interface which is used to check whether a certain value is valid or not.

public interface IValidation<in T>
{
    bool IsValid( T value );
}

Notice how T is made contravariant by using the in keyword? Not only values of type T can be validated, but also any extended type. This recent feature of C# won’t help a bit in the following scenario however. During reflection you can only use this interface when you know the complete type, including the generic type parameters. In order to support any type, you would have to check for any possible type and cast to the correct corresponding interface.

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

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 ...

Hardly entertaining, nor maintainable. What we actually need is covariance in T, or at least something that looks like it. We want to treat a more concrete IValidation<T> as IValidation<object>. For perfectly good reasons covariance is only possible when the type parameter is only used as output, otherwise objects of the wrong type could be passed. In the given scenario however, where we know only the correct type will ever be passed, this shouldn’t be a problem.

The solution is using a proxy class which implements our less generic interface and delegates all calls to the actual instance, doing the required casts where necessary.

public class LessGenericProxy : IValidation<object>
{
    readonly IValidation<string> _toWrap;

    public LessGenericProxy( IValidation<string> toWrap )
    {
        _toWrap = toWrap;
    }

    public bool IsValid( object value )
    {
        return _toWrap.IsValid( (string)value );
    }
}

With the power of Reflection.Emit, such classes can be generated at runtime! RunSharp is a great library which makes writing Emit code feel like writing ordinary C#. It’s relatively easy (compared to using Emit) to generate the proxy class. The end result looks as follows:

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

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

Of course the proxy should be cached when used multiple times. Originally I also attempted to proxy classes instead of just interfaces by extending from them. This only works properly for virtual methods. Since non-virtual methods can’t be overridden there is no way to redirect the calls to the required inner instance.

Source code can be found in my library: Whathecode.System.Reflection.Emit.Proxy.

Creating delegates during reflection with unbound instances

Previously I discussed how to work around the variance limitations of the Delegate.CreateDelegate method. CreateDelegate has quite a few overloads, and acts differently based on the parameters which are passed. It also allows you to create open instance or closed static delegates. Without going into too much detail:

  • Closed delegate: an instance is bound to the delegate along with the method. In practice this means when calling the delegate, it will always operate on the same instance.
  • Open delegate: not bound to a specific target object until invocation time. An instance on which the method should operate is passed as first argument during invocation.

For now, I will only discuss creating open instance delegates. These allow you to invoke an instance method, while passing a first argument, specifying the instance on which it should be invoked.

Divide your programs into methods that perform one identifiable task. Keep all of the operations in a method at the same level of abstraction. – Kent Beck’s Smalltalk Best Practice Patterns

In an attempt to better follow this principle, better known as the Single Level of Abstraction (SLAP) principle, I’ve split up the CreateDelegate method into two helper methods. One to create ‘simple’ delegates, and one to create open instance delegates. Later, an additional third method could be added to create closed static delegates.

By ‘simple’ delegates I mean delegates of which the signature matches that of MethodInfo. More particularly, the method has the same amount of arguments than the delegate.

public static TDelegate CreateDelegate<TDelegate>(
    MethodInfo method,
    object instance = null,
    CreateOptions options = CreateOptions.None )
    where TDelegate : class
{ ... }

By default, this method results in a simple CreateDelegate call. Instead of having to pass the delegate type as an argument a generic approach is used, eliminating the need to cast the returned delegate. When the options argument is set to CreateOptions.Downcasting, this method behaves like the CreateDowncastingDelegate method from my previous post. Downcasts from the delegate argument types and return type to the required types of the method are generated where needed.

The helper method to create open instance delegates looks as follows:

/// <summary>
///   Creates a delegate of a specified type that represents a method
///   which can be executed on an instance passed as parameter.
/// </summary>
/// <typeparam name = "TDelegate">
///   The type for the delegate. This delegate needs at least one (first) type parameter
///   denoting the type of the instance which will be passed.
///   E.g. Action<ExampleObject, object>,
///        where ExampleObject denotes the instance type and object denotes
///        the desired type of the first parameter of the method.
/// </typeparam>
/// <param name = "method">The MethodInfo describing the method of the instance type.</param>
/// <param name = "options">Options which specify what type of delegate should be created.</param>
public static TDelegate CreateOpenInstanceDelegate<TDelegate>(
    MethodInfo method,
    CreateOptions options = CreateOptions.None )
    where TDelegate : class
    { ... }

The comments indicate clearly what TDelegate should look like. Of course, no instance can be passed, clearly specifying it needs to be specified in the delegate type. Furthermore, the passed MethodInfo is required to be an instance method. All these measures are meant to clarify this specific usage of CreateDelegate. Additionally, similar to passing CreateOptions.Downcasting to the other helper method, it allows you to break the variance safety of the ordinary CreateDelegate method.

Both helper functions can be found in DelegateHelper.cs. I also added MethodInfo extension functions to the reflection extensions, resulting in a more concise syntax.

Example usage:

MethodInfo toUpperMethod = typeof( string ).GetMethod( "ToUpper", new Type[] { } );
Func<string, string> toUpper = toUpperMethod.CreateOpenInstanceDelegate<Func<string, string>>();
string upper = toUpper( "test" ); // Will result in "TEST".

Creating delegates during reflection for unknown types

Using reflection, .NET allows you to create delegates based on MethodInfo objects. Calling a delegate is a lot more performant than using Invoke as already discussed by Jon Skeet. His results showed a delegate invocation is 600 times as fast. Plenty of reason to go through the extra effort of creating and caching a delegate. However, in a real world scenario when adding behavior to an existing class by using reflection, you’ll quickly encounter several limitations when using CreateDelegate. This post shows you where, and how to easily work around them.

In my previous article I discussed covariance and contravariance. One of the limitations of CreateDelegate is it only allows you to create delegates according to those rules. This makes perfect sense, but isn’t always desirable in practical use cases.

How would you go about creating a delegate for any method which is attributed with CallThis when the exact type of the argument is unknown? You do know the method’s signature matches Action, and only the correct type will ever be passed to the delegate.

class CallThisAttribute : Attribute { }
class SomeClass
{
    [CallThis]
    public void SomeMethod( AnyType type ) { ... }
}

...

SomeClass instance = new SomeClass();
MethodInfo methodToCall = instance.GetType().GetAttributedMethod( typeof( CallThisAttribute ) );

// The following would work, but during reflection we don't know about AnyType.
Action<AnyType> action
    = Delegate.CreateDelegate( typeof( Action<AnyType> ), instance, methodToCall );

// The following throws an ArgumentException, since the method can only be called with AnyType.
Action<object> unkownArgument
    = Delegate.CreateDelegate( typeof( Action<object> ), instance, methodToCall );

Creating this delegate isn’t impossible. This is how you would go about creating it ordinarily.

SomeClass instance = new SomeClass();
Action<object> unknownArgument = o => instance.SomeMethod( (AnyType)o );
unknownArgument( new AnyType() );  // This works ...
unknownArgument( 10 );  // ... but this will throw an InvalidCastException.

Can this downcast be generated at runtime? Yes, and the easiest approach seems to be by using expression trees. Instead of passing the type of the required delegate to create as an argument, I opted to use a generic approach. Its usage looks as follows:

Action<object> unknownArgument
    = DelegateHelper.CreateDowncastingDelegate<Action<object>>( instance, methodToCall );

Any possible delegate type can be passed. All parameters of the method, and return value are matched with those of the delegate, and casts are created where necessary.

public static TDelegate CreateDowncastingDelegate<TDelegate>( object instance, MethodInfo method )
{
    MethodInfo delegateInfo = MethodInfoFromDelegateType( typeof( TDelegate ) );

    // Create delegate original and converted arguments.
    var delegateTypes = delegateInfo.GetParameters().Select( d => d.ParameterType );
    var methodTypes = method.GetParameters().Select( m => m.ParameterType );
    var delegateArgumentExpressions
        = CreateDelegateArgumentExpressions( delegateTypes, methodTypes );

    // Create method call.
    Expression methodCall = Expression.Call(
        instance == null ? null : Expression.Constant( instance ),
        method,
        delegateArgumentExpressions.ConvertedArguments );

    // Convert return type when necessary.
    Expression convertedMethodCall
        = delegateInfo.ReturnType == method.ReturnType
              ? methodCall
              : Expression.Convert( methodCall, delegateInfo.ReturnType );

    return Expression.Lambda<TDelegate>(
        convertedMethodCall,
        delegateArgumentExpressions.OriginalArguments
        ).Compile();
}

I’m still not entirely satisfied with the name of the method. CreateDowncastingDelegate refers to the fact that downcasts are generated where necessary. Its usage looks more like an upcasted delegate however. If anyone can come up with a better name, be sure to let me know.

The entire source code can be found in the FCL Extension library. In there you can also find another method which will most likely be the subject of my next post.