Archive for category .NET

Fluent Design System in Windows 10: Aesthetics over Usability?

At the Build 2017 conference, Microsoft revealed upcoming changes to the way applications will be (and can be) designed, introducing their Fluent Design System in the Windows 10 Fall Creators Update. This update focuses on the role which light, depth, motion, material, and scale can play in the design of user interfaces (UIs): really nice and impressive stuff which can certainly be used to improve user experiences. However, given that it has been a recurring theme in UI design to prioritize aesthetics over usability, I want to take a critical look at one of the newly introduced features—reveal highlight.

Reveal uses light to make interactive elements stand out. Light illuminates the interactive element the user can interact with, revealing hidden borders. The light also gently illuminates other interactive elements that are nearby.

… The Reveal behavior does this by revealing the clickable content’s container when the pointer is nearby.

For example, see the difference between the calculator application in Windows 10 and the same calculator using ‘reveal’.

reveal

Certainly an improvement, but at this point I feel it is worthwhile to take a couple more steps back to compare this with what the calculator looked like in Windows 7.

win7-calc

Less pretty, to be sure, but notice in particular how there is no need to hover over the memory buttons to perceive that they can be clicked and where to do so. To me, the UI modifications introduced as part of Windows 8 and 10 are two steps back and ‘reveal’ is one step forward, mitigating some of the earlier mistakes: the power of perceived affordances took a backseat to ‘flat design’, effectively stripping many UI elements of their clarity in how they can be used: where to click, can they be clicked, and what type of element it is. The question I would like to ask is: Should buttons ever look like ordinary labels in the first place?

While it is awesome to have additional development tools available to create more pleasing ‘on hover’ effects, conceptually this is nothing new. From a design perspective, it would still not make sense to require a user to hover over important UI elements to only then be able to interpret what they are. Therefore, at this point I would merely like to highlight that ‘reveal’ with the purpose of revealing functionality should likely be used sparingly, only for non-essential user interface elements. Whether or not the memory buttons in the calculator are ‘important’ (and potential alternate ways of visualizing them) is a different discussion to be had.

As researchers in user interface design know, perceived affordances improve usability. Conversely, I blogged about how the lack of affordances in the window manager of Windows 10 complicates resizing and moving windows around. Ironically, this was demonstrated perfectly by Ashish during his presentation on how to use the Fluent Design System features in XAML, as he spent 32 seconds on resizing a window to its desired size while narrating “Sorry. If this machine cooperates.” and Tim helpfully instructing him that he is “anchoring [the window] too high …”.

The (literal) bottom line of this post: great new stuff in Windows (and XAML), but I hope this post serves as a warning to think of usability first when using the new Fluent Design System features, aesthetics only second.

Advertisements

Leave a comment

Non-generic Wrapper instead of Base Class or Interface

A common solution to treating a generic type as non-generic is to implement an interface or make the generic type extend from a non-generic base class. Among other reasons, this allows you to instantiate a collection of generic types. There are varying implementations of this pattern, but they all seem to share this common strategy. In this article I present an alternate approach favoring composition over inheritance which I argue is more appropriate in circumstances where the intent is to break type safety.

To clarify, I will follow Steven Lowe’s argumentation on misuse of inheritanceSemantically, the statement “SomeType<T> is SomeType” is not always true; SomeType<T> is not a proper subtype of SomeType when the base type exposes type-specific bits (as Jon Skeet puts it). In this case the extending type imposes more restrictions than the base type. When there is a need to expose type-specific bits (implying type casts are involved), using inheritance does not follow the Liskov substitution principle (LSP). Regardless, such subtypes seem common. Just consider Microsoft’s List<T> implementing a non-generic IList which to quote Eric Lippert, “is a bit odd, since List for any type other than object does not fulfill the full contract of IList”.

From this it becomes clear there are real-world scenarios where a generic type needs to be accessed in a non-generic way (e.g. during reflection as I argued previously). Type safety is temporarily broken, leaving it is up to the caller to guarantee only the correct types are used. How then to improve on the following common implementation? Note that since the non-generic interface is implemented explicitly, the caller consciously needs to cast to ISomeType, somewhat alleviating the problem of possible misuse.

public interface ISomeType
{
    object Value { get; set; }
}

public class SomeType<T> : ISomeType
{
    public T Value { get; set; }

    // Explicit implementation (cast to ISomeType needed to be used).
    object ISomeType.Value
    {
        get { return this.Value; }
        set { this.Value = (T)value; }
    }
}

We need a non-generic interface but are given a generic interface, so why not apply the adapter pattern?

An adapter helps two incompatible interfaces to work together. […] Interfaces may be incompatible but the inner functionality should suit the need.

Since the class we are trying to create an adapter for is generic, our adapter implementation needs to be generic too. However, we can expose the non-generic interface which will be used by the client. Just like a usual adapter, the non-generic wrapper contains the adaptee and refers all of the IAdaptor calls to it, casting to T where necessary.

 

public interface IAdaptor
{
    object Value { get; set; }
}

class NonGenericWrapper<T> : IAdaptor
{
    private readonly Adaptee<T> _adaptee;

    public NonGenericWrapper(Adaptee<T> adaptee)
    {
        _adaptee = adaptee;
    }

    public object Value
    {
        get { return _adaptee.Value; }
        set { _adaptee.Value = (T) value; }
    }
}

Furthermore, to facilitate the creation of this non-generic wrapper (and in addition hiding its implementation) the wrapper can optionally be initialized from within the adaptee and added as a member. This approach seems similar to how user interface controls in .NET expose the window handle they operate on as a member variable, allowing for unsafe operations when the control class does not offer the required functionality.

public class Adaptee<T>
{
    public T Value { get; set; }

    public IAdaptor NonGeneric { get; private set; }

    public Adaptee()
    {
        NonGeneric = new NonGenericWrapper<T>(this);
    }
}
Pattern which can be used to expose a non-generic interface from within a generic class.

Pattern which can be used to expose a non-generic interface from within a generic class.

This approach still requires boiler-plate code to be written and maintained (NonGenericWrapper<T>), but no longer breaks the Liskov substitution principle. Ideally creating non-generic wrappers can be automated, of which I created an early prototypical solution before (not functional in all scenarios). Until then, this solution provides a more robust implementation for complex scenarios using generics, like collections of generic types with varying type parameters on which the same operations need to be performed. This might be the topic of a future post.

Leave a comment

Generic TypeConverter for XAML

TypeConverter‘s in WPF are part of the underlying mechanism which allow you to assign values to attributes of complex types within XAML using plain strings. For example, whenever you specify Point‘s.

<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">

Typically, you specify a TypeConverter for a certain type by applying the TypeConverterAttribute to it.

[TypeConverterAttribute( typeof( PointConverter ) )]
public struct Point : IFormattable

Since attribute arguments cannot use type parameters, this prevents you from specifying a generic TypeConverter for a generic class. I came across this issue while implementing a type converter to support specifying instances of my generic Interval class from XAML. The following is not possible.

// attribute argument cannot use type parameters
[TypeConverter( typeof( IntervalTypeConverter<T, TSize> ) )]
public class Interval<T, TSize>

However, you can write a non-generic TypeConverter which is capable of converting strings to several different target types. When using XAML you can obtain a IDestinationTypeProvider service through the context which is passed to the ConvertFrom method. From here you can retrieve the fully specified target type, including generic type parameters. Through reflection you can then call a Parse method on the specific type to take care of initializing an instance of the desired type. An example for Interval can be found in my library.

public override object ConvertFrom(
    ITypeDescriptorContext context,
    CultureInfo culture,
    object value )
{
    var typeProvider =
      (IDestinationTypeProvider)context.GetService( typeof( IDestinationTypeProvider ) );
    Type targetType = typeProvider.GetDestinationType();

    // ... convert to desired target type using a parsing method

    return base.ConvertFrom( context, culture, value );
}

However, it is important to note that this type provider will only work for XAML, since the IDestinationTypeProvider service is only provided by XAML’s ServiceProviderContext. It is thus not desirable to add this TypeProvider to types which work independent from XAML, like my Interval class. In addition this would require referencing the System.Xaml assembly.

How then to make XAML use this type provider without applying the attribute to the type definition? One option is applying the TypeConverter attribute on a per-property basis.

The per-property type converter technique is particularly useful if you choose to use a property type from Microsoft .NET Framework or from some other library where you cannot control the class definition and cannot apply a TypeConverterAttribute there.

However, this implies a lot of redundancy, having to apply the attribute to every property of that specific type. Using TypeDescriptor.AddAttributes() you can assign a TypeConverter at runtime.

TypeDescriptor.AddAttributes(
  typeof( Interval<,> ),
  new TypeConverterAttribute( typeof( IntervalTypeConverter ) ) );

Any subsequent TypeDescriptor.GetConverter() call will then return the converter for the specified type. Unfortunately this does not work for XAML, since XAML does not seem to take component modifications at runtime into account. Therefore, in order for this to work, we need to implement this runtime behavior ourselves. Recall that XAML does load TypeConverter‘s specified in TypeConverterAttribute‘s. We can thus use a special type converter which redirects its implementation to a converter loaded through TypeDescriptor to hook into XAML’s type conversion runtime. I implemented a RedirectTypeConverter which can be used as a base class for this exact purpose. Each of its methods first ensures the converter is initialized using TypeDescriptor, and then redirects the call to this converter. When TypeDescriptor.GetConverter( _type ) returns the redirecting type converter itself, this means no converter was specified using TypeDescriptor, hence no conversion is supported for this type.

protected RedirectTypeConverter( Type type )
{
	_type = type;
}

public override object ConvertFrom(
	ITypeDescriptorContext context,
	CultureInfo culture,
	object value )
{
	InitializeConverter();
	return _converter.ConvertFrom( context, culture, value );
}

public void InitializeConverter()
{
	if ( _converter != null )
	{
		return;
	}

	_converter = TypeDescriptor.GetConverter( _type );
	if ( _converter.GetType() == GetType() )
	{
		string message = string.Format(
		  "Conversion failed. Converter for {0} is missing in TypeDescriptor.", _type );
		throw new InvalidOperationException( message );
	}
}
class RedirectIntervalTypeConverter : RedirectTypeConverter
{
	public RedirectIntervalTypeConverter()
		: base( typeof( Interval<,> ) )
	{
	}
}

Applying this converter using TypeConverterAttribute to generic types thus allows redirecting type conversion to a converter which supports multiple target types in environments which provide information about the target type (like XAML using IDestinationTypeProvider). You only need to add the converter once, and it will be supported for all of your dependency properties using them.

TypeDescriptor.AddAttributes(
  typeof( Interval<,> ),
  new TypeConverterAttribute( typeof( IntervalTypeConverter ) ) );

2 Comments

Interval: Generic Ranges in C#

There is no doubt about it; out of all the programming languages I ever experimented with, C# has offered me the most streamlined positive development experience so far. It is a modern, ever-evolving language, which now that C# and the whole .NET framework is turning to open source, is guaranteed an even greater future. However, some core constructs commonly available in other languages, like intervals which I introduce an implementation of in this post, are missing. E.g., Ruby has had Ranges for quite some time.

A Range represents an interval—a set of values with a beginning and an end.

Straightforward, but due to the lack of support for generic calculations in C#, a hassle to implement. However, as introduced by Marc Gravell, with some runtime compilation trickery involving expression trees, far from out of reach. I’ve had an Interval<T> class within my core library for quite some time, but just now refactored it to also support more complex intervals, e.g. an interval between two DateTime instances, which thus represents a TimeSpan.

Without further ado, an example of what using this looks like in practice.

// Mockup of a GUI element and mouse position.
var timeBar = new { X = 100, Width = 200 };
int mouseX = 180;

// Find out which date on the time bar the mouse is positioned on,
// assuming it represents whole of 2014.
var timeRepresentation = new Interval<int>( timeBar.X, timeBar.X + timeBar.Width );
DateTime start = new DateTime( 2014, 1, 1 );
DateTime end = new DateTime( 2014, 12, 31 );
var thisYear = new Interval<DateTime, TimeSpan>( start, end );
DateTime hoverOver = timeRepresentation.Map( mouseX, thisYear );

// If the user clicks, zoom in to this position.
double zoomLevel = 0.5;
double zoomInAt = thisYear.GetPercentageFor( hoverOver );
Interval<DateTime, TimeSpan> zoomed = thisYear.Scale( zoomLevel, zoomInAt );

// Iterate over the interval, e.g. draw labels.
zoomed.EveryStepOf( TimeSpan.FromDays( 1 ), d => DrawLabel( d ) );

As you might notice, the timeRepresentation interval has just one generic parameter (Interval<int>), whereas thisYear has two (Interval<DateTime, TimeSpan>). The less generic (one type parameter) class is a simple wrapper around the more generic base type which has two type parameters; the first denotes the type used to represent any position within the range, whereas the second type is used to represent differences between these positions. When these types are the same, the simplified wrapper can be used. Likewise, a TimeInterval wrapper can easily be created if you find Interval<DateTime, TimeSpan> to be too verbose.

Worth noting here to understand how it works under the covers is the constructor which sets two public static fields used during operations when conversions to double are needed. Arguably, this could be improved by having a factory creating the intervals and using constructor injection instead.

public TimeInterval( DateTime start, bool isStartIncluded, DateTime end, bool isEndIncluded )
	: base( start, isStartIncluded, end, isEndIncluded )
{
	ConvertDoubleToSize = d => new TimeSpan( (long)Math.Round( d ) );
	ConvertSizeToDouble = s => s.Ticks;
}

Once you start incorporating the notion of an interval in your programming arsenal you will be amazed by the opportunities which present themselves where to use them! Some actual examples within my core library:

To get an impression of the full range of currently supported operations, check out the unit tests.

1 Comment

Generic Attributes in C#

As awesome as C# is, once you want to do some more advanced stuff with attributes, you quickly run into several limitations. There is even a Microsoft Connect entry on this issue.

  • Attributes can’t be generic, since a generic type cannot derive from ‘Attribute’.
  • An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.

Using TypeDescriptor and a whole bunch of custom code these limitations can be overcome. In this post I will describe an easier straightforward way by which to create something similar to generic attributes, ignoring the second issue for now. In future posts I will discuss how and where these attributes can be used for something I previously called attribute metabehavior.

The idea is quite straightforward; although attributes can’t be generic, nothing prevents you from adding generic instances to them. These instances can later be extracted at run time using reflection. The trick of course is initializing the generic instance. Once you know the Activator class can create instances by knowing their Type definition, the solution becomes self-evident. By simply passing the generic type as an argument to the attribute, instance creation can be delegated to Activator. Optional constructor arguments can also be passed as attribute arguments.

public class BehaviorAttribute : Attribute
{
	/// <summary>
	///   The dynamically created instance of the type passed to the constructor.
	/// </summary>
	public object DynamicInstance { get; private set; }

	/// <summary>
	///   Create a new attribute and initialize a certain type.
	/// </summary>
	/// <param name = "dynamicType">The type to initialize.</param>
	/// <param name = "constructorArguments">
	///   The arguments to pass to the constructor of the type.
	/// </param>
	public BehaviorAttribute(
		Type dynamicType,
		params object[] constructorArguments )
	{
		DynamicInstance =
			Activator.CreateInstance( dynamicType, constructorArguments );
	}
}

This attribute can then be be applied as follows:

class Answer<T>
{
	public T Value;

	public Answer( T value )
	{
		Value = value;
	}
}

[BehaviorAttribute( typeof( Answer<int> ), 42 )]
class TheWorld {}

Using ordinary reflection, the instance can be extracted.

Type type = typeof( TheWorld );
var behavior = (BehaviorAttribute)type
    .GetCustomAttributes( typeof( BehaviorAttribute ), false ).First());
var genericInstance = (Answer<int>)behavior.DynamicInstance;
int answer = genericInstance.Value;

What follows is up to you, how will you use this? I’ll describe a few advanced use cases in subsequent posts.

5 Comments

Conditional project or library reference in Visual Studio

In case you were wondering why you haven’t heard from me in a while, I’ve been busy, which isn’t really of much importance unless you know me on a personal level. What is relevant is that I recently graduated with a master in Game and Media Technology and am now in the process of making the project which I have been working on for my thesis open source. I’m very anxious to announce it, so you’ll read a lot more about it in the near future.

The project uses two of my other open source libraries, located in separate repositories. Adding these projects to the solution and referencing them as project references has the advantage of easier debugging and facilitates making changes to them. However, I do not want to force anyone interested in making changes to the main project to having to download the other repositories as well. Therefore I opted to use DLL references. This has one major downside. Whenever I do make changes to one of the dependent libraries, I need to manually copy the newly compiled DLLs to the main project. Wouldn’t it be easy to use two separate solution files, one with project references, and one with DLL references?

The first problem you’ll encounter is project references aren’t stored in the .sln file but in the .csproj file, which makes sense really. Since the .csproj file is shared by both solutions, we’ll have to conditionally reference either our DLLs or our projects, depending on which solution the project is opened in. This is possible using MSBuild, but you will need to create a new project configuration. Setting the configuration of the project differently in one solution from the other allows you to differentiate between the two of them. The following is part of a .csproj file which conditionally loads a reference by checking whether the project configuration is set to ‘Debug With Project References’.

  <Choose>
    <When Condition="'$(Configuration)' == 'Debug With Project References'">
      <ItemGroup>
        <ProjectReference Include="..\SomeProject\SomeProject.csproj">
          <Project>{6CA7AB2C-2D8D-422A-9FD4-2992BE62720A}</Project>
          <Name>SomeProject</Name>
        </ProjectReference>
      </ItemGroup>
    </When>
    <Otherwise>
      <ItemGroup>
        <Reference Include="SomeProject">
          <HintPath>..\Libraries\SomeProject.dll</HintPath>
        </Reference>
      </ItemGroup>
    </Otherwise>
  </Choose>

You could very well stop here, but I wanted to resolve another issue as well. Unless you follow a really strict folder structure, and force everyone else who wants to open your solution to do the same, the path used to reference the project can vary between people. Remember we are using separate repositories here, and the referenced projects aren’t included in the repository of the main solution, so relative paths don’t necessarily work. It is possible to specify the paths in an external ‘configuration’ file, and importing it into the .csproj file. Additionally, as a fallback when the project can’t be found at the given path, it is also useful to load the DLL instead. This way you can choose to load one or more, but not necessarily all references as a project reference.

The configuration file (ProjectReferences.txt):

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition="$(Configuration) == 'Debug With Project References'">
	<SomeProject>..\SomeProject</SomeProject>
  </PropertyGroup>
</Project>

Segment from the .csproj file:

  <Import Project="..\ProjectReferences.txt" />
  <Choose>
    <When Condition="Exists($(SomeProject))">
      <ItemGroup>
        <ProjectReference Include="$(SomeProject)\SomeProject.csproj">
          <Project>{6CA7AB2C-2D8D-422A-9FD4-2992BE62720A}</Project>
          <Name>SomeProject</Name>
        </ProjectReference>
      </ItemGroup>
    </When>
    <Otherwise>
      <ItemGroup>
        <Reference Include="SomeProject">
          <HintPath>..\Libraries\SomeProject.dll</HintPath>
        </Reference>
      </ItemGroup>
    </Otherwise>
  </Choose>

Notice the project configuration check now occurs in the configuration file. The ‘$(SomeProject)’ property is only set when using the ‘Debug With Project References’ configuration, thus in all other scenarios the DLL will be loaded instead since the ‘Exists()‘ check will fail.

One last issue remains. We still need to manually copy the latest compiled DLLs to the ‘Libraries’ folder when changes were made for the solution which uses them to work as expected. We can exploit the fact that we now have the relevant project paths available in the configuration file. Using a post build event you can call a script which parses the XML data, and copies the DLLs to the correct location. This script should be called conditionally, only for the solution which includes the project references, and ideally also only for a Release build. I used a small Ruby script which offers a lot more flexibility than a Batch script.

The post build event:

if "$(SolutionName)" == "SomeSolution With Project References" if "$(ConfigurationName)" == "Release" ruby $(SolutionDir)UpdateLibraryDlls.rb $(SolutionDir)

1 Comment

Null Checks for Event Handlers, an Aspect Solution

There is no denying events in C# are a great step forward from more traditional approaches where a lot of boilerplate code needed to be written. I choose C# events over Java’s solution to the Observer pattern any day.

… but, there is one pesky little issue I have with them. By design, it’s really easy to introduce bugs using them. How often have you encountered a NullReferenceException because you didn’t check whether an event handler was null prior to calling it? As a more experienced developer you might choose one out of the following two options.

1. Repeated null checks

Always check whether an event isn’t null prior to calling it. Additionally, you need to copy the event handler to a local variable, otherwise another thread might unsubscribe from the event causing the handler to be null again after you did the null check.

EventHandler handler = SomeEvent;
if ( handler != null )
{
    handler( ... );
}

2. Always subscribe one empty delegate

There might be a small cost of constantly having to call one extra function when the event is raised, but it solves the problem of having to do repeated null checks throughout the code while simultaneously solving the multi-threading issue.

public event EventHandler SomeEvent = delegate {};

The Aspect way

I prefer the second approach, and don’t see any reason why it shouldn’t be used by default, other than a smarter compiler which could take care of this in a ‘cleaner’ manner. That’s why over the weekend I’ve spent some time seeing how PostSharp could help solving this cross-cutting concern. I always love showing off the result prior to explaining how I got there. It’s usage is a one liner.

[assembly: InitializeEventHandlers( AttributeTargetTypes = "Laevo.*" )]
namespace Laevo { ... }

Adding this one attribute prevents you from having to worry about events throughout the entire namespace it applies to.

How does it work?

First of all, you will need PostSharp. That’s not necessarily a bad thing, because if you are fortunate enough to be allowed to use it, or you can simply decide for yourself to buy it, you will greatly appreciate it for more than just this one possible use case.

The InitializeEventHandlersAttribute is called an aspect which is applied on events. However, using a feature of PostSharp called ‘multicasting’, you are able to apply the attribute (MulticastAttribute) on higher level elements, allowing you to choose which one of the lower level elements the aspect should apply to. In the code above, the aspect is applied on an entire assembly, but the aspect knows it should only be applied to events, which is further narrowed down using the AttributeTargetTypes parameter to events within the namespace “Laevo”, and all sub-namespaces. In order to remind the developer that a certain part of his code is enhanced by an aspect, a visualization as follows is visible within Visual Studio.

The code is short enough to paste in its entirety now, but I’ll decompose it in a minute.

[AttributeUsage( AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Event )]
[MulticastAttributeUsage( MulticastTargets.Event, AllowMultiple = false )]
[AspectTypeDependency(
    AspectDependencyAction.Commute,
    typeof( InitializeEventHandlersAttribute ) )]
[Serializable]
public class InitializeEventHandlersAttribute : EventLevelAspect
{
	[NonSerialized]
	Action<object> _addEmptyEventHandler;

	[OnMethodEntryAdvice, MethodPointcut( "SelectConstructors" )]
	public void OnConstructorEntry( MethodExecutionArgs args )
	{
		_addEmptyEventHandler( args.Instance );
	}

	IEnumerable<ConstructorInfo> SelectConstructors( EventInfo target )
	{
		return target.DeclaringType.GetConstructors(
                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
	}

	public override void RuntimeInitialize( EventInfo eventInfo )
	{
		base.RuntimeInitialize( eventInfo );

		// Construct a suitable empty event handler.
		MethodInfo delegateInfo = DelegateHelper.MethodInfoFromDelegateType(
                    eventInfo.EventHandlerType );
		ParameterExpression[] parameters = delegateInfo.GetParameters().Select( p =>
                    Expression.Parameter( p.ParameterType ) ).ToArray();
		Delegate emptyDelegate = Expression.Lambda(
                    eventInfo.EventHandlerType, Expression.Empty(),
                    "EmptyDelegate", true, parameters ).Compile();

		// Create a delegate which adds the empty handler to an instance.
		_addEmptyEventHandler = instance => eventInfo.AddEventHandler( instance, emptyDelegate );
	}
}

The steps I followed to create this aspect are documented in the PostSharp 2.1 Documentation “Adding Behaviors to Members”.

  1. Create a new class, deriving from the relevant aspect class. Since I am creating an aspect which is applied on events, I used EventLevelAspect.
  2. Choose on which part of the code your aspect will have effect. This is called an ‘advice’. Although my aspect is applied on events, the solution I used is to add an empty event handler to the events by default. This is something which can be done from the constructor. Therefore I had to use an OnMethodEntryAdvice in order to add this code to the beginning of every constructor.
[OnMethodEntryAdvice, MethodPointcut( "SelectConstructors" )]
public void OnConstructorEntry( MethodExecutionArgs args )
{
	_addEmptyEventHandler( args.Instance );
}
  1. Choosing a ‘pointcut’ is required to determine where the code needs to be added. We’ve already established it needs to be added to the start of methods by using OnMethodEntryAdvice, but we haven’t established which methods it needs to be applied to yet. By using a MethodPointcut, this task is delegated to a separate method of which you pass the name. In my case, this method doesn’t do much more than returning all the constructors of the current type.
IEnumerable<ConstructorInfo> SelectConstructors( EventInfo target )
{
	return target.DeclaringType.GetConstructors(
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
}
  1. We are nearly done, although there is one part of the code I skipped over which is quite interesting nonetheless. The OnMethodEntryAdvice calls the delegate _addEmptyEventHandler(), but where did this come from? Overriding RuntimeInitialize gives you the chance to initialize objects which the advice will require for the specific element the aspect applies to. Using reflection to analyze the passed EventInfo object, a suitable empty event handler can be constructed using Expression Trees. This is required since we don’t have the luxury of using an equivalent to ‘delegate {}’. Finally a simple delegate is created which can add the empty delegate to the event of any given instance.
public override void RuntimeInitialize( EventInfo eventInfo )
{
	base.RuntimeInitialize( eventInfo );

	// Construct a suitable empty event handler.
	MethodInfo delegateInfo = DelegateHelper.MethodInfoFromDelegateType( eventInfo.EventHandlerType );
	ParameterExpression[] parameters = delegateInfo.GetParameters().Select( p => Expression.Parameter( p.ParameterType ) ).ToArray();
	Delegate emptyDelegate
		= Expression.Lambda( eventInfo.EventHandlerType, Expression.Empty(), "EmptyDelegate", true, parameters ).Compile();

	// Create a delegate which adds the empty handler to an instance.
	_addEmptyEventHandler = instance => eventInfo.AddEventHandler( instance, emptyDelegate );
}

… and all that just to eliminate ‘= delegate {}’? Yes, I can be quite stubborn sometimes. 🙂

UPDATE:

This code has since been slightly altered in order to also support events with generic parameters within generic types. Thank you Anupheaus, for reporting this issue! Be sure to check out the latest code on github. A discussion of the problem, and how to work around it can be found in my answer on Stack Overflow.

9 Comments