A Simple Delegate Example
I was recently working on a code generator and I made use of some simple delegates and I thought that I would share a few ideas.
Some folks may be wondering what is a delegate. You can think of a delegate as a type safe function pointer. It’s a type which can be passed around like any other type and it can be invoked which calls the original method that it’s pointing to. Lets look at a delegate type declaration:
public delegate void DoSomething();
This basically creates a delegate type called DoSomething that can point to a method that takes no arguments and returns void.
Say you have a method:
public void HeresSomething() { //put something here }
then you can create a new instance of our delegate and have it point to that method like:
DoSomething myDelegate = new DoSomething(HeresSomething);
ReSharper tells me that you can abbreviate this syntax like so:
DoSomething myDelegate = HeresSomething;
Now myDelegate can be passed around and then executed just like a method which will call the real method HeresSomething():
myDelegate();
This becomes really valuable is when you have delegates that take arguments and return values as you will see in a moment.
In my particular real life case, I have some .NET data transfer objects (DTOs) which I want to code generate equivalent Flex ActionScript objects so I can move data back and forth via serialization. These DTOs can be complex types (objects within objects) so I will need to unwind the object hierarchy to determine what to generate.
Let’s look at an example without using delegates:
class TypeUnwinder { public void Unwind(Type type, List<Type> allTypes) { if (allTypes.Contains(type)) return;allTypes.Add(type); UnwindProperties(type, allTypes); UnwindMethods(type, allTypes); } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindProperties(Type type, List<Type> allTypes) { <span style="color: #0000ff">foreach</span> (PropertyInfo propertyInfo <span style="color: #0000ff">in</span> type.GetProperties()) { Unwind(propertyInfo.PropertyType, allTypes); } } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindMethods(Type type, List<Type> allTypes) { <span style="color: #0000ff">foreach</span> (MethodInfo methodInfo <span style="color: #0000ff">in</span> type.GetMethods()) { Unwind(methodInfo.ReturnType, allTypes); UnwindParameters(methodInfo, allTypes); } } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindParameters(MethodInfo methodInfo, List<Type> allTypes) { <span style="color: #0000ff">foreach</span> (ParameterInfo parameterInfo <span style="color: #0000ff">in</span> methodInfo.GetParameters()) { Unwind(parameterInfo.ParameterType, allTypes); } }}
This code works ok but my real case is much more complex. I actually have to unwind a couple of different times for different reasons and I have multiple checks for attributes and I ignore certain types. I want to reuse my pattern of unwinding with different logic. I can do this using a delegate. Instead of passing a List around, I can have the UnwindType method simply call a delegate that takes a Type. The calling class supplies the delegate and figures out what to do with the Type when it’s called.
First I create a delegate that returns bool that takes one argument of type Type:
public delegate bool DoSomethingWithTypeDelegate(Type type);
Then we modify our class by removing the references to the List and have it take in an instance of our delegate in the constructor:
class TypeUnwinder2 { private readonly DoSomethingWithTypeDelegate doSomethingWithType;<span style="color: #0000ff">public</span> TypeUnwinder2(DoSomethingWithTypeDelegate doSomethingWithType) { <span style="color: #0000ff">this</span>.doSomethingWithType = doSomethingWithType; } <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> UnwindType(Type type) { <span style="color: #0000ff">if</span>(!doSomethingWithType(type)) <span style="color: #0000ff">return</span>; UnwindProperties(type); UnwindMethods(type); } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindProperties(Type type) { <span style="color: #0000ff">foreach</span> (PropertyInfo propertyInfo <span style="color: #0000ff">in</span> type.GetProperties()) { UnwindType(propertyInfo.PropertyType); } } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindMethods(Type type) { <span style="color: #0000ff">foreach</span> (MethodInfo methodInfo <span style="color: #0000ff">in</span> type.GetMethods()) { UnwindType(methodInfo.ReturnType); UnwindParameters(methodInfo); } } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindParameters(MethodInfo methodInfo) { <span style="color: #0000ff">foreach</span> (ParameterInfo parameterInfo <span style="color: #0000ff">in</span> methodInfo.GetParameters()) { UnwindType(parameterInfo.ParameterType); } }}
Now a calling class can control what actually happens when a Type is hit (remember, this is just example code):
class Program { static readonly List<Type> types = new List<Type>();<span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[] args) { TypeUnwinder2 unwinder = <span style="color: #0000ff">new</span> TypeUnwinder2(IndexType); unwinder.UnwindType(<span style="color: #0000ff">typeof</span>(SomeCustomTypeToUnwind)); <span style="color: #0000ff">foreach</span> (Type type <span style="color: #0000ff">in</span> types) { Console.WriteLine(type.FullName); } } <span style="color: #0000ff">static</span> <span style="color: #0000ff">bool</span> IndexType(Type type) { <span style="color: #0000ff">if</span> (!types.Contains(type)) { types.Add(type); <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>; } <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>; }}
Notice how we pass in IndexType to the TypeUnwinder2 constructor (the delegate is created for you). If we wanted to see the delegate, we could have done:
TypeUnwinder2 unwinder = new TypeUnwinder2(new DoSomethingWithTypeDelegate(IndexType));
So adding a delegate allowed me to decouple my unwinding pattern from the work that happens as a result of the unwinding. Yeah!
Here’s a version that uses another delegate to reuse a single foreach loop. It’s a bit ridiculous , but it might be fun to decipher.
class TypeUnwinder3 { private DoSomethingWithTypeDelegate doSomethingWithType;<span style="color: #0000ff">public</span> TypeUnwinder3(DoSomethingWithTypeDelegate doSomethingWithType) { <span style="color: #0000ff">this</span>.doSomethingWithType = doSomethingWithType; } <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> UnwindType(Type type) { <span style="color: #0000ff">if</span> (!doSomethingWithType(type)) <span style="color: #0000ff">return</span>; UnwindItems(type.GetProperties(), UnwindProperty); UnwindItems(type.GetMethods(), UnwindMethod); } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindItems<T>(IEnumerable<T> items, Action<T> process) { <span style="color: #0000ff">foreach</span> (T item <span style="color: #0000ff">in</span> items) { process(item); } } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindProperty(PropertyInfo propertyInfo) { UnwindType(propertyInfo.PropertyType); } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindMethod(MethodInfo methodInfo) { UnwindType(methodInfo.ReturnType); UnwindItems(methodInfo.GetParameters(), UnwindParameter); } <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> UnwindParameter(ParameterInfo parameterInfo) { UnwindType(parameterInfo.ParameterType); }}
