InternetException

About coding and whatnot.

Genereting proxies during runtime using Reflection.Emit

clock October 7, 2016 08:29 by author n.podbielski

Reflection.Emit is very powerful tool. It creates IL code and since C# is converted into IL too, we have the same functionality as in C# and even more. It is very powerful and at the same time very complicated. Because of that it is worth to discuss how and for what it should be used. One idea is to create dynamic code with automatic implementations of interfaces - proxy types.

 

Things you can do but probably will not.

First thing we can try is to implement automatic calls to OnPropertyChanged in properties setters.

Let's start with simple WPF application with single window defined in XAML as follows.

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" HorizontalAlignment="Center"
                    VerticalAlignment="Center">
            <TextBlock Text="{Binding Model.IntValue}"></TextBlock>
        </StackPanel>
        <StackPanel Grid.Row="1" 
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center">
            <Button Command="{Binding Increment}" Content="Increment" Padding="10"></Button>
        </StackPanel>
    </Grid>
</Window>

View model for main window looks like this.

using System.Windows.Input;

namespace TestApp
{
    public class MainWindowViewModel
    {
        private ICommand _increment;

        public MainWindowViewModel()
        {
            Model = new MainModel();
        }

        public ICommand Increment => _increment ?? (_increment = new Command(OnIncrement));

        public MainModel Model { get; set; }

        private void OnIncrement()
        {
            Model.Increment();
        }
    }
}

As you can see we have single text block and single button. View model have single integer value and command that runs method on model.

Model looks like this.

namespace TestApp
{
    public class MainModel
    {
        public int IntValue { get; set; }

        public void Increment()
        {
            IntValue++;
        }
    }
}

Ok. After button click text block value should be incremented.

How to do that? Binding should listen to OnPropertyChange call of IPropertyChanged interface. But for a lot of properties it is quite bit of work to implement all of them manually. Instead, we can do it automatically with proxy created via Reflection.Emit.

public static class ProxyGenerator
{
    public static T PropertyChangedProxy<T>() where T : class, new()
    {
        var type = typeof(T);
        var assemblyName = type.FullName + "_Proxy";
        var fileName = assemblyName + ".dll";
        var name = new AssemblyName(assemblyName);
        var assembly = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
        var module = assembly.DefineDynamicModule(assemblyName, fileName);
        var typeBuilder = module.DefineType(type.Name + "Proxy",
            TypeAttributes.Class | TypeAttributes.Public, type);
        typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
        var onPropertyChangedMethod = type.GetMethod("OnPropertyChanged",
            BindingFlags.Instance | BindingFlags.NonPublic);
        var propertyInfos = type.GetProperties().Where(p => p.CanRead && p.CanWrite);
        foreach (var item in propertyInfos)
        {
            var baseMethod = item.GetGetMethod();
            var getAccessor = typeBuilder.DefineMethod(baseMethod.Name, baseMethod.Attributes, item.PropertyType, null);
            var il = getAccessor.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.EmitCall(OpCodes.Call, baseMethod, null);
            il.Emit(OpCodes.Ret);
            typeBuilder.DefineMethodOverride(getAccessor, baseMethod);
            baseMethod = item.GetSetMethod();
            var setAccessor = typeBuilder.DefineMethod(baseMethod.Name, baseMethod.Attributes, typeof(void), new[] { item.PropertyType });
            il = setAccessor.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Call, baseMethod);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, item.Name);
            il.Emit(OpCodes.Call, onPropertyChangedMethod);
            il.Emit(OpCodes.Ret);
            typeBuilder.DefineMethodOverride(setAccessor, baseMethod);
        }
        var t = typeBuilder.CreateType();
        assembly.Save(fileName);
        return Activator.CreateInstance(t) as T;
    }
}

Simple overwrite of all properties of type and because of that it works without problems.

 

Minus of this solution is, even if it can be easily binded in Xaml, it can't be called easily from code. Those properties are not visible via base type since this type do not have virtual properties. Considering that type with overridden properties is dynamically created it cannot be called from code (because it do not exists in compile time). Only way to call them from code is via Reflection mechanism.

It makes it much less elegant.

 

Things you can do but probably should not

Minus of Reflection.Emit is really poor documentation of how it supposed to work and how it should be used. For example I could not find good example of how to define an event (I am talking about official Microsoft documentation). There is nothing about using TypeBuilder.DefineEvent method on MSDN. Good thing there is StackOverflow and a lot of blogs like this one. Chances are really high that someone tried the same thing before. Smile

Ok, going back to subject. Previous implementation of proxy generation lacks automatic implementation of interface INotifyPropertyChanged. You have to do it yourself in every class you want to create proxy of (or use some kind of base class, but we are talking about a problem when this is impossible or not recommended).
Good thing it is possible to implement this interface dynamically in proxy using Reflection.Emit too. To do that we need to create event PropertyChanged, which requires to:

  1. Declare event field
  2. Add event declaration
  3. Add Add accessor
  4. Add Remove accessor
  5. Define raise method.

 

Quite few things to do, since in C# you have to do 2 things to create event

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Define an event and raise method. Simple. In IL things as you see above is are much more complicated.

Ok. To implement interface dynamically we have to first add this interface to class. In Reflection.Emit this requires only single line, luckily. Smile

typeBuilder.AddInterfaceImplementation(typeof(INotifyPropertyChanged));

After that we can define event itself.

var field = typeBuilder.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);
var eventInfo = typeBuilder.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler));

As you can see we are defining field to store delegates and event itself. Both members are taken care of in C# by event definition. Also the same definition in C# creates two accessors: add and remove. We can of course creates accessors ourselves but it is very rarely needed. In IL we have to do it manually. How? First we need to explain few things.

Events in C# are handled by Delegate types. Delegate class have static method Combine, which combines two delegates into invocation list. And this mechanism is used to store all handlers in single value of a event field. When event is raised all methods from invocation list are called. To be able to use Delegate.Combine we have to retrieve this method via Reflection.

var combine = typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) });

Now we can create add acessor method and implement it.

var ibaseMethod = typeof(INotifyPropertyChanged).GetMethod("add_PropertyChanged");
var addMethod = typeBuilder.DefineMethod("add_PropertyChanged",
    ibaseMethod.Attributes ^ MethodAttributes.Abstract,
    ibaseMethod.CallingConvention,
    ibaseMethod.ReturnType,
    new[] { typeof(PropertyChangedEventHandler) });
var generator = addMethod.GetILGenerator();
var combine = typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) });
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Call, combine);
generator.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
generator.Emit(OpCodes.Stfld, field);
generator.Emit(OpCodes.Ret);
eventInfo.SetAddOnMethod(addMethod);

Few things needs clarification. First off all, we are implementing interface method (even if interface do not have this method declared explicitly) and we need this method metadata for implementation to work. After we get interface method info we can use it to create override. Overridden method have to have the same parameters, return type, calling conventions and attributes (without Abstract, because it is method with implementation).


There are only few IL codes in implementation, but it needs explanation anyway.

First IL is not a C# so you need to look at it a little differently. In C# method you have state in form of set of temporary variables (if it is a pure method) and in class itself. In IL you have only stack which is kind of a state of a IL method. Variables on stack determine source of fields, instance methods, and methods parameters. In above example what was most difficult to understand for me were first two lines. Why there is a loading of first method argument two times to stack? Lets look at picture below. First 'row' is a stack after execution of first two codes: Ldarg_0.

We load source instance (C# this) two times which is always first argument of a instance method (even if this is not visible in C#). After that we have two items on stack, both are reference to the same object. After next operation (Ldfld) which takes only one argument (assembly operations usually takes none or one argument), we also have two values on stack (source instance and value of field, which replaces second reference to source instance). Next operations (Ldarg_1) loads second argument of method on top a stack which causes stack to contains three values. Top two items from stack are passed to Delegate.Combine call, which replaces two items on top of stack with new combined delegate. Next IL code (Castclass) replaces item on top by casting it to appropriate type of event, which is then used to set field of source instance with new value of event handler (Stfld). Returned value is void so whole rest of stack is discarded and none value is returned from method (if method is non void top item from stack is returned).

With added implementation of method add_PropertyChanged, most of this code can be reused for remove accessor, but instead of Delegate.Combine we use Delegate.Remove.

var ibaseMethod = typeof(INotifyPropertyChanged).GetMethod("remove_PropertyChanged");
var removeMethod = typeBuilder.DefineMethod("remove_PropertyChanged",
    ibaseMethod.Attributes ^ MethodAttributes.Abstract,
    ibaseMethod.CallingConvention,
    ibaseMethod.ReturnType,
    new[] { typeof(PropertyChangedEventHandler) });
var remove = typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) });
var generator = removeMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Call, remove);
generator.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
generator.Emit(OpCodes.Stfld, field);
generator.Emit(OpCodes.Ret);
eventInfo.SetRemoveOnMethod(removeMethod);

Much more interesting is implementation of raise method. C# implementation is pretty straightforward

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

We check if event have any handlers and invoke all of them. In IL things are much more complicated.

var methodBuilder = typeBuilder.DefineMethod("OnPropertyChanged",
    MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig |
    MethodAttributes.NewSlot, typeof(void),
    new[] { typeof(string) });
var generator = methodBuilder.GetILGenerator();
var returnLabel = generator.DefineLabel();
var propertyArgsCtor = typeof(PropertyChangedEventArgs).GetConstructor(new[] { typeof(string) });
generator.DeclareLocal(typeof(PropertyChangedEventHandler));
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Brfalse, returnLabel);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Newobj, propertyArgsCtor);
generator.Emit(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke"));
generator.MarkLabel(returnLabel);
generator.Emit(OpCodes.Ret);
eventInfo.SetRaiseMethod(methodBuilder);
return methodBuilder;

Definition of this method (attributes) is taken from ILDASM application, used to inspect IL code generated from above C# code. I did not experimented with it nor I dwelled why it is written like that. After all it is not a point and specialist and Microsoft know what they are doing (at least I hope so Wink). My intention was to have IL code to work as much as C# event as it is possible.

New things among IL operation codes is label declaration. Thing is: in assemblers language you do not have blocks, closures, functions etc. You only have stream of operations and jumps for flow control. So instead of if statement there is a label for return from method - if value of event handlers are null (no handlers for event) program jumps to end of method. If there are handlers they are invoked and method ends.

Lets go through operations step by step.

First, of course we load instance of object (which is first argument with index of 0). After that we load field of from that instance represented by PropertyChanged field of event. After loading on to of a stack we store it in method variable (which is why DeclareLocal is called earlier). It is because we need this value twice: first to check if it is not null and second for calling it.  Brfalse operation check if value is boolean false. In C# we have to check if value of a class is null or not null explicitly. In IL assembly language the same operation, checks if value is boolean false, integer 0 or null. If it is 'false' program control jumps to return label. If not, it continues and loads value of event again from local variable (first one was discarded by Brfalse operation). Next we load instance of proxy MainModelProxy and name of changed property (in second parameter of method, at 1 index - Ldarg_1). Newobj operation calls given constructor. Since this constructor takes one parameter (name of property) this stack value is replaced by new object. So we have two items in stack: instance of MainModelProxy class and new instance of PropertyChangedEventArgs. With those values available we can safely invoke Invoke method of PropertyChangedEventHandler (which is kind of static method since it do not takes first argument as instance). This method do not returns value so we can return from dynamic OnPropertyChanged method with Ret operation.

Ok. After removing implementation from MainModel class and running this code we will see the same results as before: label text will show next value of integer after each button press, which proves that IL implementation of event works fine. Why there is a problem then? After all, this section is titled things you 'should not do', right? Let's jump back to C# implementation in MainModel class and inspect details with ILDASM.exe. We will see following IL code in add_PropertyChanged method.

.method public hidebysig newslot specialname virtual final 
        instance void  add_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler 'value') cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       41 (0x29)
  .maxstack  3
  .locals init (class [System]System.ComponentModel.PropertyChangedEventHandler V_0,
           class [System]System.ComponentModel.PropertyChangedEventHandler V_1,
           class [System]System.ComponentModel.PropertyChangedEventHandler V_2)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      class [System]System.ComponentModel.PropertyChangedEventHandler TestApp.MainModel::PropertyChanged
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  ldarg.1
  IL_000b:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
                                                                                          class [mscorlib]System.Delegate)
  IL_0010:  castclass  [System]System.ComponentModel.PropertyChangedEventHandler
  IL_0015:  stloc.2
  IL_0016:  ldarg.0
  IL_0017:  ldflda     class [System]System.ComponentModel.PropertyChangedEventHandler TestApp.MainModel::PropertyChanged
  IL_001c:  ldloc.2
  IL_001d:  ldloc.1
  IL_001e:  call       !!0 [mscorlib]System.Threading.Interlocked::CompareExchange(!!0&,
                                                                                                                                                    !!0,
                                                                                                                                                    !!0)
  IL_0023:  stloc.0
  IL_0024:  ldloc.0
  IL_0025:  ldloc.1
  IL_0026:  bne.un.s   IL_0007
  IL_0028:  ret
} // end of method MainModel::add_PropertyChanged

As you can see it is entirely different. There is a loop that checks for a value returned from System.Threading.Interlocked.CompareExchange method! What for? Probably because of thread safe code for changing of event handlers invocation list. And this is out of a box with new C# compiler. Since there is no really a point in informing a C# users of every change of how C# compiler compiles code to IL, if you are interested you have to inspect it yourself. It is a lot of work to keep your IL code in line with what Microsoft do. So even if you can write IL code that suppose to do the same as IL code generated by C# compiler - you can't be sure unless you check it yourself. Add to that a very troublesome process of creating such IL code (you can't debug it; you can't really tell what is wrong with it - you just will be greeted with ubiquitous 'IL code is not correct' error without details) - I strongly urge you to write IL code with Reflection.Emit that only do:

  1. Calls to other C# methods.
  2. Casts objects to other types.

 

Any other, more complicated code can be written in C# and then invoked via IL. It really do not matter if method is instance one (unless it uses state of object) or static one. For example in my opinion it is better to have method that takes care of null-checking, creating instance of PropertyChangedEventArgs and calling PropertyChangeHandler. Consider following static method. 

public static class PropertyChangedInvoker
{
    public static void Invoke(INotifyPropertyChanged sender,
        PropertyChangedEventHandler source, string propertyName)
    {
        source?.Invoke(sender, new PropertyChangedEventArgs(propertyName));
    }
}

This static method in static class can be safely called from IL and it those all the logic that was previously implemented in IL inside OnPropertyChanged method! Thing is we have really easy to read and (most important!) debuggable, testable code. In IL it is not possible. The only thing left to do in IL is to call this method with correct set of parameters.

var methodBuilder = typeBuilder.DefineMethod("OnPropertyChanged",
    MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig |
    MethodAttributes.NewSlot, CallingConventions.Standard | CallingConventions.HasThis, typeof(void),
    new[] { typeof(string) });
var generator = methodBuilder.GetILGenerator();
var returnLabel = generator.DefineLabel();
generator.DeclareLocal(typeof(PropertyChangedEventHandler));
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Call, typeof(PropertyChangedInvoker).GetMethod("Invoke"));
generator.MarkLabel(returnLabel);
generator.Emit(OpCodes.Ret);
eventInfo.SetRaiseMethod(methodBuilder);
return methodBuilder;

As you can see in IL we only collect set of parameters. Sender from this in first argument of a instance method OnPropertyChanged, event field value and property name for event arguments constructor.

On the side note IMHO it is funny that we can't directly invoke event outside of a class unless we access event field value first Smile

Someone may say that this IL is not really that less complicated. However if you will look closer it is totally independent from changes of event definition, event arguments class definition and event delegate definition. If you will not change number of arguments needed by raise method and arguments class parameters (of course there is really small chance that those things change in PropertyChangeEventHandler since it is .NET class) you are safe and sound.

Point from all of this is:

Use as little IL as possible, since working with it in VS is quite painful.

 

Things you can do and probably should because it's cool.

I am currently working on mobile Xamarin applications. One of most missing features is WCF (and other services) proxies. It is possible to use third party libraries, but I could not find one that could suits my needs 100%. Because of that I decided to write proxy generating mechanism myself. This is ideal place for Reflection.Emit since you have almost the same code for every HTTP/HTTPS call with small differences like HTTP method (GET, POST etc.) or return/parameter type(s).
Consider following self-hosted JSON WCF service defined as follow.

public class Service : IService
{
    public int Add(AddRequest req)
    {
        return req.FirstNumber + req.SecondNumber;
    }

    public string Test(string param)
    {
        return param;
    }
}

As you can see we have two methods: Test (simple echo) and Add that sums two arguments. Nothing fancy, but we do not need anything more since it is enough to show use of Reflection.Emit in this scenario.
Contract is defined in interface IService.

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebInvoke(Method = "POST",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json)]
    int Add(AddRequest req);

    [OperationContract]
    [WebGet]
    string Test(string param);
}

First one uses POST HTTP method and transports messages using JSON. Second one: GET and simple strings.

Self hosting is done by simple code in second test, console application.

static void Main(string[] args)
{
    var serviceHost = new ServiceHost(typeof(Service), new Uri("http://localhost:8081"));
    using (serviceHost)
    {
        var seb = new WebHttpBehavior
        {
            DefaultOutgoingRequestFormat = WebMessageFormat.Json,
            DefaultOutgoingResponseFormat = WebMessageFormat.Json,
            FaultExceptionEnabled = true
        };
        serviceHost.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
        var e = serviceHost.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
        e.Behaviors.Add(seb);
        serviceHost.Open();
        Console.WriteLine("Service ready...");
        Console.ReadLine();
        serviceHost.Close();
    }
}

Ok. This is really simple code. Almost minimal code to run self-hosted JSON service. How to call it from WPF application? HttpClient .NET class is more than enough.

private void OnCallService()
{
    using (var client = new HttpClient(new HttpClientHandler()))
    {
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var addRequest = new AddRequest
        {
            FirstNumber = First,
            SecondNumber = Second
        };
        var serializeObject = JsonConvert.SerializeObject(addRequest);
        var call = client.PostAsync("http://localhost:8081/add",
            new StringContent(serializeObject, Encoding.UTF8, "application/json"));
        try
        {
            call.Wait();
            var result = call.Result.Content;
            Sum = (int)JsonConvert.DeserializeObject(result.ReadAsStringAsync().Result, typeof(int));
        }
        catch (System.Exception)
        {
        }
    }
}

Simple using statement with HttpClient instance, configuring it for POST request with JSON string and deserializing result value from call, to appropriate type.

How we can automate this with Reflection.Emit and proxy generation? First of all we need some type as base for our proxy. Luckily WCF services have contracts and they are usually shared with client anyway. We can implement this interface! Smile

Ok, first of all lets go back to ProxyGenerator class. We can add new method ServiceProxy to it for generating service proxies.

public static T ServiceProxy<T>(string baseUrl) where T : class
{
    var serviceInterface = typeof(T);
    if (serviceInterface.IsInterface)
    {
        var assemblyName = serviceInterface.FullName + "_Proxy";
        var fileName = assemblyName + ".dll";
        var name = new AssemblyName(assemblyName);
        var assembly = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
        var module = assembly.DefineDynamicModule(assemblyName, fileName);
        var implemntationName = serviceInterface.Name.StartsWith("I") ?
            serviceInterface.Name.Substring(1) : serviceInterface.Name;
        var typeBuilder = module.DefineType(implemntationName + "Proxy",
            TypeAttributes.Class | TypeAttributes.Public);
        typeBuilder.AddInterfaceImplementation(serviceInterface);
        foreach (var method in serviceInterface.GetMethods().Where(m => !m.IsSpecialName))
        {
            var customAttributes = method.GetCustomAttributes<OperationContractAttribute>()
                .SingleOrDefault();
            if (customAttributes != null)
            {
                var webInvokeAttr = method.GetCustomAttribute<WebInvokeAttribute>();
                var webGetAttr = method.GetCustomAttribute<WebGetAttribute>();
                ImplementServiceMethod(baseUrl, typeBuilder, method, webInvokeAttr, webGetAttr);
            }
            else
            {
                throw new Exception("Service interface has to be marked with correct method attribute!");
            }
        }
        var type = typeBuilder.CreateType();
        assembly.Save(assemblyName);
        return (T)Activator.CreateInstance(type);
    }
    return null;
}

First few lines is nothing new (already done in proxies for property changed event) nor it is interesting. Fun begins with adding service implementation to our new type. We of course need service interface in proxy type and that is why AddInterfaceImplementation method is used. Next thing to do is to search for all interface methods (that are not properties accessors; since all get_{property} and set_{property} methods have IsSpecialName set to true). In all methods we search for WeGet or WebInvoke attribute. Those attributes are required in service methods since without it we do not know what kind of url or HTTP method should be used. Core implementation of service method call is done by ImplementServiceMethod method.

private static void ImplementServiceMethod(string baseUrl, TypeBuilder typeBuilder, MethodInfo method,
                                            WebInvokeAttribute webInvokeAttr, WebGetAttribute webGetAttr)
{
    var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
    var methodBuilder = typeBuilder.DefineMethod(method.Name, method.Attributes ^ MethodAttributes.Abstract,
            method.CallingConvention, method.ReturnType,
            parameterTypes);
    var il = methodBuilder.GetILGenerator();
    var serviceCallMethod = typeof(ProxyGenerator).GetMethod("BaseServiceCall",
        BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(parameterTypes[0], method.ReturnType);

    var url = new Uri(new Uri(baseUrl), method.Name).AbsoluteUri;
    if (webGetAttr != null)
    {
        url = url + "?" + method.GetParameters()[0].Name + "=";
    }

    il.Emit(OpCodes.Ldstr, url);
    il.Emit(OpCodes.Ldstr, webGetAttr != null ? "GET" : "POST");
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Call, serviceCallMethod);
    il.Emit(OpCodes.Ret);
}

Core of the logic is handled by adding IL codes. But first we need to define method override using the same parameters, return type, method attributes and calling conventions as interface method (again attributes are the same except for Abstract one, since this one marks only abstract methods and interface methods). Of course for simplicity we use only single parameter for implementation. If you are using DTO for services methods, they should only have one parameter (DTO class). Second, if you have more than one parameter you certainly should use DTO class (it makes rewriting, refactoring much easier, which happens always, sooner or later); third if you have more than one custom DTO class method (there is really no point in doing that) you probably doing something wrong.

Anyway if your service method have more than one parameter you should refactor it to use only one and if it is not possible you can easily change collection of IL codes to load one (or more) extra parameter before calling BaseServiceCall method.

Then we change url if service method should be called with GET (because parameter should be serialized for query string). Of course here is the place to implement url template (i.e. /customer/{id}), but this is simple example so call ToString on request object is enough to make this works. After that we can actually create new method body. Since this is proxy method and whole work is done by BaseServiceCall, we just load three parameters (method url, HTTP method string, and parameter of service method) and then execute call to method defined as follow.

public static TReturn BaseServiceCall<TParam, TReturn>(string url, string method, TParam param)
{
    using (var client = new HttpClient(new HttpClientHandler()))
    {
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var serializeObject = JsonConvert.SerializeObject(param);
        var stringContent = new StringContent(serializeObject, Encoding.UTF8, "application/json");
        Task<HttpResponseMessage> call;
        if (method == "POST")
        {
            call = client.PostAsync(url, stringContent);
        }
        else
        {
            call = client.GetAsync(url + param);
        }
        var result = call.Result.Content;
        return (TReturn)JsonConvert.DeserializeObject(result.ReadAsStringAsync().Result, typeof(TReturn));
    }
}

With above code we can change our WPF application and test if this works. Below Xaml should be added inside MainWindow.xaml file.

<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Vertical"
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
    <TextBlock Text="Service proxy test" FontWeight="Bold" />
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition Height="20" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Grid.Row="0" Text="First arg" />
        <TextBlock Grid.Column="1" Grid.Row="0" Text="Second arg" />
        <TextBox Grid.Column="0"
                        Grid.Row="1" x:Name="First" Width="100" Text="{Binding First}" />
        <TextBox Grid.Column="1"
                        Grid.Row="1"
                        x:Name="Second" Width="100" Text="{Binding Second}" />
    </Grid>
    <TextBlock x:Name="Sum" Text="{Binding Sum}" />
</StackPanel>
<StackPanel HorizontalAlignment="Center" Grid.Row="1"
                Grid.Column="1"
            VerticalAlignment="Center">
    <Button Command="{Binding CallService}" 
            Content="Call Add" Padding="10" />
</StackPanel>
<Grid Grid.Row="2" Grid.Column="1"
                HorizontalAlignment="Center"
            VerticalAlignment="Center">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100"  />
        <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0" Text="Param:" />
    <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding EchoParam}" />
    <TextBlock Grid.Row="1" Grid.Column="0" Text="Result:" />
    <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Echo}" />
    <Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="Call Test" Command="{Binding CallEcho}" />
</Grid>

Buttons binds to commands in view model handled by two functions.

private void OnCallEcho()
{
    var serviceProxy = ProxyGenerator.ServiceProxy<IService>("http://localhost:8081");
    Echo = serviceProxy.Test(EchoParam);
}

private void OnCallService2()
{
    var serviceProxy = ProxyGenerator.ServiceProxy<IService>("http://localhost:8081");
    Sum = serviceProxy.Add(new AddRequest
    {
        FirstNumber = First,
        SecondNumber = Second,
    });
}

Very simple code. First create proxy with interface and then call interface method. It can't be any simpler. Smile

After starting WPF application we can try it out. After trying it out yourself you should see similar results as in below GIF.

As you can see it works without a problems.

Of course there is no need for new proxy every time we want to call service and since proxy do not have any state it can be used as singleton instance. Also there is no need to create new type every time proxy is created. Assembly is saved as .dll file on disk and can be very easily loaded to domain and proxy type can be reused.

Reflection.Emit is ideal for this scenario. We can create very easily proxy types from interface and simple manipulation of arguments, make base method do all heavy lifting. It is also really easy to maintain since you can change behavior of all methods in single base method. For example add logging, exception handling, alternative service server if first one will not respond etc.

Example application can be downloaded from here Generator-master.zip (22.62 kb) or from Github.

If you want to try it out yourself remember to start both projects (Service and TestApp) and run VS in administrator mode (it is required to start self-hosted WCF).



Faster than Reflection: Delegates. Part 3.

clock September 2, 2016 09:15 by author n.podbielski

This is third article in series, that explains how to create delegates for public and non-public members of public, non-public or not known in compile-time types. If you are not familiar with previous articles and looking for detailed explanation of how delegates works, how they are created and why, I strongly encourage you to read first two. If you are just looking for a way to create delegates for methods or constructors it is not necessary.

In first and second article in series, we covered:

  1. Static
    1. Properties
    2. Fields
    3. Methods
  2. Instance
    1. Properties
    2. Fields
    3. Indexers
    4. Methods
  3. Constructors

Now it is time to cover following members.

  1. Generic Methods
  2. Events

 

Generic methods

Previously we do not covered very important feature of C# regarding methods. If you read header of this section, you already know what I am talking about Smile. In C# there is possible to write generic methods, that do not have rigid parameters types or rigid return type, because they may vary and depends of type parameters. Most of DelegateFactory class methods are generic. How we can call those methods via delegates? Main problem is that we cannot, or at least not that easy. In reality every version of generic method with different set of type parameters is different method and we need different delegate for that set of parameters.

 

Static generic methods

Consider following method in TestClass.

public static T StaticGenericMethod<T>() where T : new ()
{
    return new T();
}

public static T StaticGenericMethod<T>(T param)
{
return param;
}

First is really simple generic method without parameter with return type from type parameter. There are lot of types in C# world that have default parameterless constructor, so we can use it and create very basic generic method that do actually something meaningful Smile. Second one is even simpler (it just returns the same object of type given by type parameter) but is important to show that is overload of generic method that takes different set of parameters.

Both are static methods so we can use StaticMethod methods, right? Yes we can and it will not work, because we cannot create correct delegate for first StaticGenericMethod example (it will throw error because passed delegate type is not compatible) or will return null if at least one of parameters is of varied type (we cannot search for method overload by its parameters if we do not know them because they differ from type parameters). Solution for those problems are new overloads that will take type parameters (or new parameters with types ) to apply to generic method.

With passing type parameters for delegate is the same problem as with indexers and methods (static and instance) members types. There are really no limits to number of parameter types (aside from reason and 16 limit in Action and Func classes) so we would have to write different StaticMethod and InstanceMethod overload for every number of type parameters. This makes little sense and from experience I can say that mostly methods have one or two type parameters. I probably wrote at some point method with 3 but I do not recall that. This is why (and consistency with other methods of DelegateFactory) support for up 3 type parameters will be enough, I think. For every other case array of types for types parameters will sufficient.

But first we need to obtain method info for generic method with possible overloads in mind. Overload can be any combination of parameters and number of type parameters. For example you can have two overloads with no parameters if they differ with number of type parameters. Or you can have overloads with the same type parameter (or none) but with different set of parameters types. Consider below methods.

public static T StaticGenericMethod<T>() where T : new()
{
    return new T();
}

public static T StaticGenericMethod<T>(T param)
{
    return param;
}

public static T StaticGenericMethod<T>(T param, int i) where T : ITestInterface
{
    return param;
}

public static T StaticGenericMethod<T>(T param, int i, bool p) where T : struct
{
    return param;
}

public static T1 StaticGenericMethod<T1, T2>() where T1 : new()
{
    return new T1();
}

public static T1 StaticGenericMethod<T1, T2, T3>(int i) where T1 : new()
{
    return new T1();
}

Those are all perfectly valid methods and because of that earlier version of GetStaticMethod method will not work. Why? Reflection do not allow us to easily find generic method overload and Type.GetMethod will throw an exception, if there is more than one overload for the same set of parameters (which is perfectly possible if one or more methods are generic). How to remedy this problem? We can catch AmbiguousMatchException when there is more than one overload and check all methods for the generic one we are looking for. To do that we need to compare two pair of sets: first set of parameters we are looking for and set pf type parameters with correct constraints.

private static MethodInfo GetStaticMethodInfo(Type source, string name, Type[] parametersTypes, Type[] typeParameters = null)
{
    MethodInfo methodInfo = null;
    try
    {
        methodInfo = (source.GetMethod(name, BindingFlags.Static, null, parametersTypes, null) ??
                        source.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic, null, parametersTypes, null)) ??
                        source.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, parametersTypes, null);
    }
    catch (AmbiguousMatchException)
    {
        //swallow and test generics
    }
    //check for generic methods
    if (typeParameters != null)
    {
        var ms = source.GetMethods(BindingFlags.Static)
                .Concat(source.GetMethods(BindingFlags.NonPublic | BindingFlags.Static))
                .Concat(source.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static));
        foreach (var m in ms)
        {
            if (m.Name == name && m.IsGenericMethod)
            {
                var parameters = m.GetParameters();
                var genericArguments = m.GetGenericArguments();
                var parametersTypesValid = parameters.Length == parametersTypes.Length;
                parametersTypesValid &= genericArguments.Length == typeParameters.Length;
                if (!parametersTypesValid)
                {
                    continue;
                }
                for (var index = 0; index < parameters.Length; index++)
                {
                    var parameterInfo = parameters[index];
                    var parameterType = parametersTypes[index];
                    if (parameterInfo.ParameterType != parameterType
                        && parameterInfo.ParameterType.IsGenericParameter
                        && !parameterInfo.ParameterType.CanBeAssignedFrom(parameterType))
                    {
                        parametersTypesValid = false;
                        break;
                    }
                }
                for (var index = 0; index < genericArguments.Length; index++)
                {
                    var genericArgument = genericArguments[index];
                    var typeParameter = typeParameters[index];
                    if (!genericArgument.CanBeAssignedFrom(typeParameter))
                    {
                        parametersTypesValid = false;
                        break;
                    }
                }
                if (parametersTypesValid)
                {
                    methodInfo = m.MakeGenericMethod(typeParameters);
                    break;
                }
            }
        }
    }
    return methodInfo;
}

This is much more complicated than before! But do not worry, I will explain everything Smile.

Previous code is inside try statement. First change is one extra parameter with set of type parameters that should be checked against every overload of method generic arguments number and all constraints. If we do look for generic method (typeParameter is not null), we are switching to looking methods one by one. After retrieving all methods of type, with all visibilities, we have to filter them by name. Then we check if method is generic. If it is we have to check number of parameters and type parameters. If those are correct we have to compare them with delegate parameters and type arguments at the same position. Checking for parameters is not that easy as comparing only types because parameters can have type from type parameters, which can have constraints. Because of that we have to check for type of parameter and if it is different (generic parameter have special generic type) we have to check if parameter is generic and if its generic type can represent type of parameter we are looking for. In example int type can be represent by parameter of generic type T with constraint of struct. This may be a little hard to understand without knowledge about detail of IsAssignableFrom method. There is of course Type.IsAssignableFrom method, but strangely it was not working correctly since simple argument without constraints could not be matched with any class. Code of both is the same except for check as below, which was causing false results.

RuntimeType toType = this.UnderlyingSystemType as RuntimeType;
if (toType != null)
    return toType.IsAssignableFrom(c);

I do not know why, but after removing it and creating new method without it works as it should and i.e. T type parameter in method without type parameter constraints:

public static T StaticGenericMethod<T>(T param)

can be assigned from TestClass type, when we check with new implementation of IsAssignableFrom.

public static bool CanBeAssignedFrom(this Type destination, Type source)
{
    if (source == null || destination == null)
    {
        return false;
    }

    if (destination == source || source.IsSubclassOf(destination))
    {
        return true;
    }

    if (destination.IsInterface)
    {
        return source.ImplementsInterface(destination);
    }

    if (!destination.IsGenericParameter)
    {
        return false;
    }

    var constraints = destination.GetGenericParameterConstraints();
    return constraints.All(t1 => t1.CanBeAssignedFrom(source));
}

private static bool ImplementsInterface(this Type source, Type interfaceType)
{
    while (source != null)
    {
        var interfaces = source.GetInterfaces();
        if (interfaces.Any(i => i == interfaceType
            || i.ImplementsInterface(interfaceType)))
        {
            return true;
        }

        source = source.BaseType;
    }
    return false;
}

Above method have to be used in two situations. First we have to compare given set of parameters of delegate with parameters of a method. This was done previously automatically by searching for method in Type.GetMethod method. But now, since we know, that it is possible to have two generic methods with the same set of parameters, we have to check, against desired types, every generic method overload ourselves. If method do not have generic parameters comparing is easy: just check if  two Type type instances are equal. But if method have generic parameters we have to compare type parameter constraints of this parameter. This is done by CanBeAssignedFrom method.

If our set of parameters is correct we have to compare type parameters in similar way. Every provided concrete type have to be check against type parameter of method at the same index and its constraints. It is also done by CanBeAssignedFrom method.

If both sets are correct it means we have our desired generic method overload and it can used to produce method with concrete types by Type.MakeGenericMethod.

Ok. Let's cover static methods. First case when we know all delegate types, then unknown types (by objects) and after that we will do the same for instance methods.

First new overloads for generics are very easy to implement. Since we already have working GetStaticMethodInfo method, that not only searches for method info, but also creates non-generic method with specified type parameters, we can use returned object to create delegate as for non-generic delegates. The only difference are extra type parameters for delegate method... well type parameters. It will look much more clear in code.

public static TDelegate StaticMethod<TSource, TDelegate, TParam1>(string name)
    where TDelegate : class
{
    return typeof(TSource).StaticMethod<TDelegate>(name, typeof(TParam1));
}

public static TDelegate StaticMethod<TSource, TDelegate, TParam1, TParam2>(string name)
    where TDelegate : class
{
    return typeof(TSource).StaticMethod<TDelegate>(name, typeof(TParam1), typeof(TParam2));
}

public static TDelegate StaticMethod<TSource, TDelegate, TParam1, TParam2, TParam3>(string name)
    where TDelegate : class
{
    return typeof(TSource).StaticMethod<TDelegate>(name, typeof(TParam1), typeof(TParam2), typeof(TParam3));
}

public static TDelegate StaticMethod<TSource, TDelegate>(string name, params Type[] typeParameters)
    where TDelegate : class
{
    return typeof(TSource).StaticMethod<TDelegate>(name, typeParameters);
}

public static TDelegate StaticMethod<TDelegate>(this Type source, string name, params Type[] typeParameters)
    where TDelegate : class
{
    var paramsTypes = GetFuncDelegateArguments<TDelegate>();
    var methodInfo = GetStaticMethodInfo(source, name, paramsTypes, typeParameters);
    return methodInfo?.CreateDelegate(typeof(TDelegate)) as TDelegate;
}

First three are just overloads with use of 1, 2 or 3 type parameters for generic method with the same number of type parameters. Next method allow to create delegate with more type parameters. Most important is last method that do actual work of creating delegate.

To use above methods for generic methods delegate we have to call them in following way (first examplary call and then destination generic method that will be executed via delegate).

var g1 = DelegateFactory.StaticMethod<TestClass, Func<TestClass, TestClass>, TestClass>("StaticGenericMethod");
public static T StaticGenericMethod<T>(T param)

var g2 = DelegateFactory.StaticMethod<TestClass, Func<TestClass, int, TestClass>, TestClass>("StaticGenericMethod");
public static T StaticGenericMethod<T>(T param, int i) where T : ITestInterface

var g3 = DelegateFactory.StaticMethod<TestClass, Func<TestStruct, int, bool, TestStruct>, TestStruct>("StaticGenericMethod");
public static T StaticGenericMethod<T>(T param, int i, bool p) where T : struct

var g4 = DelegateFactory.StaticMethod<TestClass, Func<TestClass>, TestClass>("StaticGenericMethod");
public static T StaticGenericMethod<T>() where T : new()

var g5 = DelegateFactory.StaticMethod<TestClass, Func<TestClass>, TestClass, TestStruct>("StaticGenericMethod");
public static T1 StaticGenericMethod<T1, T2>() where T1 : new()

var g6 = DelegateFactory.StaticMethod<TestClass, Func<int, TestClass>, TestClass, TestStruct, int>("StaticGenericMethod");
public static T1 StaticGenericMethod<T1, T2, T3>(int i) where T1 : new()

var g7 = DelegateFactory.StaticMethod<TestClass, Func<int, TestClass>>("StaticGenericMethod", typeof(TestClass), typeof(TestStruct), typeof(int));
public static T1 StaticGenericMethod<T1, T2, T3>(int i) where T1 : new()

Looks very easy when explained this way Smile

We already have StaticMethod overload as extension method for Type instance. We can also write three new overloads for cases when we want to create delegates for 1, 2 or 3 type parameters and we do not know or do not want to use source type.

public static TDelegate StaticMethod<TDelegate, TParam1>(this Type source, string name)
    where TDelegate : class
{
    return source.StaticMethod<TDelegate>(name, typeof(TParam1));
}

public static TDelegate StaticMethod<TDelegate, TParam1, TParam2>(this Type source, string name)
    where TDelegate : class
{
    return source.StaticMethod<TDelegate>(name, typeof(TParam1), typeof(TParam2));
}

public static TDelegate StaticMethod<TDelegate, TParam1, TParam2, TParam3>(this Type source, string name)
    where TDelegate : class
{
    return source.StaticMethod<TDelegate>(name, typeof(TParam1), typeof(TParam2), typeof(TParam3));
}

They are used in the same way as source type passed as first type parameter.

Ok. Now we can jump to case when we do not know any of types (or do not want to use those). Produced delegate should use object type for parameters and for return value. It was done in static methods, instance methods, properties and indexers. Main problem with this function is that we cannot do it as overload of StaticMethod because one of previous overloads already allows params parameters. Any other overload with array of types would be compile error. Also having in mind, that for method without passed delegate type we have to write two methods, for void return type and for non-void types, we will create methods StaticGenericMethod and StaticGenericMethodVoid. Luckily both can be handled by the same code as StaticMethod and StaticMethodVoid with just simple change.

public static Func<object[], object> StaticGenericMethod(this Type source,
    string name, Type[] paramsTypes, Type[] typeParams)
{
    return StaticMethod<Func<object[], object>>(source, name, typeParams, paramsTypes);
}

public static Action<object[]> StaticGenericMethodVoid(this Type source,
    string name, Type[] paramsTypes, Type[] typeParams)
{
    return StaticMethod<Action<object[]>>(source, name, typeParams, paramsTypes);
}

Changed implementation of previous methods will look like this.

public static Func<object[], object> StaticMethod(this Type source,
    string name, params Type[] paramsTypes)
{
    return StaticMethod<Func<object[], object>>(source, name, null, paramsTypes);
}

public static TDelegate StaticMethod<TDelegate>(this Type source,
    string name, Type[] typeParams, Type[] paramsTypes)
    where TDelegate : class
{
    var methodInfo = GetStaticMethodInfo(source, name, paramsTypes, typeParams);
    if (methodInfo == null)
    {
        return null;
    }
    var argsArray = Expression.Parameter(typeof(object[]));
    var paramsExpression = new Expression[paramsTypes.Length];
    for (var i = 0; i < paramsTypes.Length; i++)
    {
        var argType = paramsTypes[i];
        paramsExpression[i] =
            Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType);
    }
    Expression returnExpression = Expression.Call(methodInfo, paramsExpression);
    if (methodInfo.ReturnType != typeof(void) && !methodInfo.ReturnType.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return Expression.Lambda(returnExpression, argsArray).Compile() as TDelegate;
}

public static Action<object[]> StaticMethodVoid(this Type source,
    string name, params Type[] paramsTypes)
{
    return StaticMethod<Action<object[]>>(source, name, null, paramsTypes);
}

Now with everything ready for static generic methods, we can start tests. Below calls will create delegates for different overloads of StaticGenericMethod (lines in every block) and using different overloads of StaticMethod or StaticGenericMethod (three blocks).

var g1 = DelegateFactory.StaticMethod<TestClass, Func<TestClass, TestClass>, TestClass>("StaticGenericMethod");
var g2 = DelegateFactory.StaticMethod<TestClass, Func<TestClass, int, TestClass>, TestClass>("StaticGenericMethod");
var g3 = DelegateFactory.StaticMethod<TestClass, Func<TestStruct, int, bool, TestStruct>, TestStruct>("StaticGenericMethod");
var g4 = DelegateFactory.StaticMethod<TestClass, Func, TestClass>("StaticGenericMethod");
var g5 = DelegateFactory.StaticMethod<TestClass, Func, TestClass, TestStruct>("StaticGenericMethod");
var g6 = DelegateFactory.StaticMethod<TestClass, Func<int, TestClass>, TestClass, TestStruct, int>("StaticGenericMethod");
var g7 = DelegateFactory.StaticMethod<TestClass, Func<int, TestClass>>("StaticGenericMethod", typeof(TestClass), typeof(TestStruct), typeof(int));

var g8 = Type.StaticMethod<Func<TestClass, TestClass>, TestClass>("StaticGenericMethod");
var g9 = Type.StaticMethod<Func<TestClass, int, TestClass>, TestClass>("StaticGenericMethod");
var g10 = Type.StaticMethod<Func<TestStruct, int, bool, TestStruct>, TestStruct>("StaticGenericMethod");
var g11 = Type.StaticMethod<Func, TestClass>("StaticGenericMethod");
var g12 = Type.StaticMethod<Func, TestClass, TestStruct>("StaticGenericMethod");
var g13 = Type.StaticMethod<Func<int, TestClass>, TestClass, TestStruct, int>("StaticGenericMethod");
var g14 = Type.StaticMethod<Func<int, TestClass>>("StaticGenericMethod", typeof(TestClass), typeof(TestStruct), typeof(int));

var g15 = Type.StaticGenericMethod("StaticGenericMethod", new[] { Type }, new[] { Type });
var g16 = Type.StaticGenericMethod("StaticGenericMethod", new[] { Type, typeof(int) }, new[] { Type });
var g17 = Type.StaticGenericMethod("StaticGenericMethod", new[] { typeof(TestStruct), typeof(int), typeof(bool) }, new[] { typeof(TestStruct) });
var g18 = Type.StaticGenericMethod("StaticGenericMethod", Type.EmptyTypes, new[] { Type });
var g19 = Type.StaticGenericMethod("StaticGenericMethod", Type.EmptyTypes, new[] { Type, typeof(TestStruct) });
var g20 = Type.StaticGenericMethod("StaticGenericMethod", new[] { typeof(int) }, new[] { Type, typeof(TestStruct), typeof(int) });
var g21 = Type.StaticGenericMethodVoid("StaticGenericMethodVoid", new[] { Type }, new[] { Type });

Created delegates are used in following way.

var t = g1(TestInstance);
var t2 = g2(TestInstance, 0);
var t3 = g3(new TestStruct(), 0, false);
var t4 = g4();
var t5 = g5();
var t6 = g6(0);
var t7 = g7(0);

var t8 = g8(TestInstance);
var t9 = g9(TestInstance, 0);
var t10 = g10(new TestStruct(), 0, false);
var t11 = g11();
var t12 = g12();
var t13 = g13(0);
var t14 = g14(0);

var t15 = g15(new object[] { TestInstance });
var t16 = g16(new object[] { TestInstance, 0 });
var t17 = g17(new object[] { new TestStruct(), 0, false });
var t18 = g18(new object[] { });
var t19 = g19(new object[] { });
var t20 = g20(new object[] { 0 });
g21(new object[] { TestInstance });
var t21 = TestClass.StaticGenericMethodVoidParameter;

We can also test performance of delegates for generic method against direct call and reflection.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = TestClass.StaticGenericMethod(TestInstance);
}
_stopWatch.Stop();
Console.WriteLine("Static generic method directly: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = g1(TestInstance);
}
_stopWatch.Stop();
Console.WriteLine("Static generic method proxy: {0}", _stopWatch.ElapsedMilliseconds);

var methodInfos = Type.GetMethods(BindingFlags.Static | BindingFlags.Public).Where(m => m.Name == "StaticGenericMethod" && m.IsGenericMethod && m.GetParameters().Length == 1 && m.GetGenericArguments().Length==1);
var methodInfo = methodInfos.Single();
methodInfo = methodInfo.MakeGenericMethod(Type);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = methodInfo.Invoke(null, new object[] { TestInstance });
}
_stopWatch.Stop();
Console.WriteLine("Static generic method via reflection: {0}", _stopWatch.ElapsedMilliseconds);

Above code will spawn output similar lines in console.

Static generic method directly: 1160
Static generic method proxy: 1270
Static generic method via reflection: 21591

As you can see performance is consistent with other delegates for different type of members.

 

Instance generic methods

We can now do the same for instance methods. But first, we have to change GetMethodInfo in the same way as GetStaticMethodInfo.

private static MethodInfo GetMethodInfo(Type source, string name, Type[] parametersTypes, Type[] typeParameters = null)
{
    MethodInfo methodInfo = null;
    try
    {
        methodInfo = (source.GetMethod(name, BindingFlags.Instance | BindingFlags.Public, null, parametersTypes, null) ??
                        source.GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic, null, parametersTypes, null)) ??
                        source.GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, parametersTypes, null);
    }
    catch (AmbiguousMatchException)
    {
        //swallow and test generics
    }
    //check for generic methods
    if (typeParameters != null)
    {
        var ms = source.GetMethods(BindingFlags.Instance | BindingFlags.Public)
                .Concat(source.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance))
                .Concat(source.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance));
        foreach (var m in ms)
        {
            if (m.Name == name && m.IsGenericMethod)
            {
                var parameters = m.GetParameters();
                var genericArguments = m.GetGenericArguments();
                var parametersTypesValid = parameters.Length == parametersTypes.Length;
                parametersTypesValid &= genericArguments.Length == typeParameters.Length;
                if (!parametersTypesValid)
                {
                    continue;
                }
                for (var index = 0; index < parameters.Length; index++)
                {
                    var parameterInfo = parameters[index];
                    var parameterType = parametersTypes[index];
                    if (parameterInfo.ParameterType != parameterType
                        && parameterInfo.ParameterType.IsGenericParameter
                        && !parameterInfo.ParameterType.CanBeAssignedFrom(parameterType))
                    {
                        parametersTypesValid = false;
                        break;
                    }
                }
                for (var index = 0; index < genericArguments.Length; index++)
                {
                    var genericArgument = genericArguments[index];
                    var typeParameter = typeParameters[index];
                    if (!genericArgument.CanBeAssignedFrom(typeParameter))
                    {
                        parametersTypesValid = false;
                        break;
                    }
                }
                if (parametersTypesValid)
                {
                    methodInfo = m.MakeGenericMethod(typeParameters);
                    break;
                }
            }
        }
    }
    return methodInfo;
}

As you can see code is almost the same. Difference is in binding flags - Instance instead of Static value is passed.

Now we can add new overloads. We should start with overloads with type parameters only, just like with static methods. They will look like this.

public static TDelegate InstanceMethod<TDelegate, TParam1>(string name)
    where TDelegate : class
{
    return InstanceMethod<TDelegate>(name, typeof(TParam1));
}

public static TDelegate InstanceMethod<TDelegate, TParam1, TParam2>(string name)
    where TDelegate : class
{
    return InstanceMethod<TDelegate>(name, typeof(TParam1), typeof(TParam2));
}

public static TDelegate InstanceMethod<TDelegate, TParam1, TParam2, TParam3>(string name)
    where TDelegate : class
{
    return InstanceMethod<TDelegate>(name, typeof(TParam1), typeof(TParam2), typeof(TParam3));
}

public static TDelegate InstanceMethod<TDelegate>(string name, params Type[] typeParameters)
    where TDelegate : class
{
    var paramsTypes = GetFuncDelegateArguments<TDelegate>();
    var source = paramsTypes.First();
    paramsTypes = paramsTypes.Skip(1).ToArray();
    var methodInfo = GetMethodInfo(source, name, paramsTypes, typeParameters);
    return methodInfo?.CreateDelegate(typeof(TDelegate)) as TDelegate;
}

Code is very similar to the one without support for generics and new overloads are also easy to understand.

The same case is with extension methods overloads. The only difference is extra parameters and type parameters, that are passed to GetMethodInfo method.

public static TDelegate InstanceMethod<TDelegate, TParam1>(this Type source, string name)
    where TDelegate : class
{
    return source.InstanceMethod<TDelegate>(name, new[] { typeof(TParam1) });
}

public static TDelegate InstanceMethod<TDelegate, TParam1, TParam2>(this Type source, string name)
    where TDelegate : class
{
    return source.InstanceMethod<TDelegate>(name, new[] { typeof(TParam1), typeof(TParam2) });
}

public static TDelegate InstanceMethod<TDelegate, TParam1, TParam2, TParam3>(this Type source, string name)
    where TDelegate : class
{
    return source.InstanceMethod<TDelegate>(name, new[] { typeof(TParam1), typeof(TParam2), typeof(TParam3) });
}

public static TDelegate InstanceMethod<TDelegate>(this Type source, string name, Type[] typeParams = null)
    where TDelegate : class
{
    var delegateParams = GetFuncDelegateArguments<TDelegate>();
    var instanceParam = delegateParams[0];
    delegateParams = delegateParams.Skip(1).ToArray();
    var methodInfo = GetMethodInfo(source, name, delegateParams, typeParams);
    if (methodInfo == null)
    {
        return null;
    }
    Delegate deleg;
    if (instanceParam == source)
    {
        deleg = methodInfo.CreateDelegate(typeof(TDelegate));
    }
    else
    {
        var sourceParameter = Expression.Parameter(typeof(object));
        var expressions = delegateParams.Select(Expression.Parameter).ToArray();
        Expression returnExpression = Expression.Call(Expression.Convert(sourceParameter, source),
            methodInfo, expressions.Cast<Expression>());
        if (methodInfo.ReturnType != typeof(void) && !methodInfo.ReturnType.IsClass)
        {
            returnExpression = Expression.Convert(returnExpression, typeof(object));
        }
        var lamdaParams = new[] { sourceParameter }.Concat(expressions);
        deleg = Expression.Lambda(returnExpression, lamdaParams).Compile();
    }
    return deleg as TDelegate;
}

Last two, more general methods, that only takes object parameters and returns objects, are also very similar and changed in the same way as with static generics.

public static Func<object, object[], object> InstanceGenericMethod(this Type source,
    string name, Type[] paramsTypes, Type[] typeParams)
{
    return InstanceGenericMethod<Func<object, object[], object>>(source, name, typeParams, paramsTypes);
}
        
public static Action<object, object[]> InstanceGenericMethodVoid(this Type source,
    string name, Type[] paramsTypes, Type[] typeParams)
{
    return InstanceGenericMethod<Action<object, object[]>>(source, name, typeParams, paramsTypes);
}

public static Func<object, object[], object> InstanceMethod(this Type source,
    string name, params Type[] paramsTypes)
{
    return InstanceGenericMethod<Func<object, object[], object>>(source, name, null, paramsTypes);
}
        
public static Action<object, object[]> InstanceMethodVoid(this Type source,
            string name, params Type[] paramsTypes)
{
    return InstanceGenericMethod<Action<object, object[]>>(source, name, null, paramsTypes);
}

public static TDelegate InstanceGenericMethod<TDelegate>(this Type source,
    string name, Type[] typeParams, Type[] paramsTypes)
    where TDelegate : class
{
    var methodInfo = GetMethodInfo(source, name, paramsTypes, typeParams);
    if (methodInfo == null)
    {
        return null;
    }
    var argsArray = Expression.Parameter(typeof(object[]));
    var sourceParameter = Expression.Parameter(typeof(object));
    var paramsExpression = new Expression[paramsTypes.Length];
    for (var i = 0; i < paramsTypes.Length; i++)
    {
        var argType = paramsTypes[i];
        paramsExpression[i] =
            Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType);
    }
    Expression returnExpression = Expression.Call(Expression.Convert(sourceParameter, source),
        methodInfo, paramsExpression);
    if (methodInfo.ReturnType != typeof(void) && !methodInfo.ReturnType.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return Expression.Lambda(returnExpression, sourceParameter, argsArray).Compile() as TDelegate;
}

That is all we need to support instance generic methods. Now we can write some test methods.

public T GenericMethod<T>(T s)
{
    return s;
}

public object InstanceGenericMethodVoidParameter;

public void GenericMethodVoid<T>(T s)
{
    InstanceGenericMethodVoidParameter = s;
}

To create delegates for above, we call newly created overloads the same way as for static equivalents. The only difference is one extra parameter for delegates - instance.

var ig1 = DelegateFactory.InstanceMethod<Func<TestClass, TestClass, TestClass>, TestClass>("GenericMethod");
var ig2 = Type.InstanceMethod<Func<TestClass, TestClass, TestClass>, TestClass>("GenericMethod");
var ig3 = Type.InstanceMethod<Func<object, TestClass, TestClass>, TestClass>("GenericMethod");
var ig4 = Type.InstanceGenericMethod("GenericMethod", new[] { Type }, new[] { Type });
var ig5 = Type.InstanceGenericMethodVoid("GenericMethodVoid", new[] { Type }, new[] { Type });

Delegates are called the same way as for any other instance methods delegates.

var it1 = ig1(TestInstance, TestInstance);
var it2 = ig2(TestInstance, TestInstance);
var it3 = ig3(TestInstance, TestInstance);
var it4 = ig4(TestInstance, new object[] { TestInstance });
ig5(TestInstance, new object[] { TestInstance });
var it5 = TestInstance.InstanceGenericMethodVoidParameter;

That is all we need for full support of generic methods.

As you can see main difference and disadvantage of delegates for generics is that if we want full types information we need to create separate delegate for every collection of types we need. Alternatively it is possible to create delegate for generic method with more general type. In example if generic method allows some type parameter to be only of IDisposable interface it is possible to search for method and create delegate from this method with this interface. Below code is perfectly valid in compile-time and runtime.

var g22 = Type.StaticGenericMethodVoid("StaticGenericMethodVoid", new[] { typeof(object) }, new[] { typeof(object) });
g22(new object[] { "" });
var t22 = TestClass.StaticGenericMethodVoidParameter;
g22(new object[] { TestInstance });
var t23 = TestClass.StaticGenericMethodVoidParameter;

Now we discussed pretty much everything about methods. It is time for the last type of member - events.

 

Events

Static events will not be part of this article. As I explained in first article static events are something that I would never use. If you are using them you can write me in the comments and I will update article with delegates for them Smile.

Like with properties accessor, for events we also have two accessors - add and remove. For both we will add method, with few overloads. We should create few test event first.

public event EventHandler PublicEvent;

private event EventHandler InternalEventBackend;

internal event EventHandler InternalEvent
{
    add { InternalEventBackend += value; }
    remove { InternalEventBackend -= value; }
}

protected event EventHandler ProtectedEvent;

private event EventHandler PrivateEvent;

public void InvokeInternalEvent()
{
    InternalEventBackend?.Invoke(this, new InternalEventArgs());
}

public void InvokePrivateEvent()
{
    PrivateEvent?.Invoke(this, new PrivateEventArgs());
}

public void InvokeProtectedEvent()
{
    ProtectedEvent?.Invoke(this, new ProtectedEventArgs());
}

public void InvokePublicEvent()
{
    PublicEvent?.Invoke(this, new PublicEventArgs());
}

 

Four events with different visibility. Internal event have custom accessors just to test if that kind of event also will work with delegates. Public methods for invoking events are added just for pure testing (we need a way to raise event from test code outside of TestClass type).

Since to raise an event we need to add handler first we will discuss add accessors first.

 

Event add accessors

New methods in DelegateFactory will be called EventAdd. But first we need to acquire EventInfo from reflection.

private static EventInfo GetEventInfo(string eventName, Type sourceType)
{
    return (sourceType.GetEvent(eventName)
            ?? sourceType.GetEvent(eventName, BindingFlags.NonPublic))
            ?? sourceType.GetEvent(eventName,
                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
}

Nothing fancy here. It is the same code like for any other member. Just instead of property or method it looks for event.

If we know type of object with event we want to access, know type of delegate and know its event arguments type, things are really simple. We just need to pass valid delegate type in order to create delegate from accessor method.

public static Action<TSource, EventHandler<TEventArgs>> EventAdd<TSource, TEventArgs>(string eventName)
{
    var sourceType = typeof(TSource);
    var eventInfo = GetEventInfo(eventName, sourceType);
    return (Action<TSource, EventHandler<TEventArgs>>)
            eventInfo?.AddMethod.CreateDelegate(typeof(Action<TSource, EventHandler<TEventArgs>>));
}

It works the same as creating delegates for get accessor of properties. For example for TestClass.PublicEvent event it will create delegate, that could be represented by below lambda.

Action<TestClass, EventHandler<TestClass.PublicEventArgs>> d = (i, h) => i.PublicEvent += h;

Consider now case with unknown source type or when this type just do not matter. After all event handlers always have first parameter of type object so it is not really necessary from user point of view. The only problem in this case is necessity to cast instance parameter from object to correct type with event. As before, we need expressions for that.

public static Action<object, EventHandler<TEventArgs>> EventAdd<TEventArgs>(
    this Type source, string eventName)
{
    var eventInfo = GetEventInfo(eventName, source);
    if (eventInfo != null)
    {
        var instanceParameter = Expression.Parameter(typeof(object));
        var delegateTypeParameter = Expression.Parameter(typeof(EventHandler<TEventArgs>));
        var lambda = Expression.Lambda(Expression.Call(Expression.Convert(instanceParameter, source),
                                        eventInfo.AddMethod, delegateTypeParameter),
                        instanceParameter, delegateTypeParameter);
        return (Action<object, EventHandler<TEventArgs>>)lambda.Compile();
    }
    return null;
}

Created lambda expression just calls event info AddMethod on converted to source type instance parameter, with handler from second parameter. And as usually this is much easier to understand in form of a lambda Smile

Action<object, EventHandler<TestClass.PublicEventArgs>> d = (i, h) => ((TestClass)i).PublicEvent += h;

How about a case, when we know type of class and we do not know type of event arguments, i.e. when event is private? The only way to create delegate is via expressions (similar problem to situation when we do not know parameters of method). Unfortunately this is a little more complicated since every event handler takes object and some type that derives from EventArgs (or not since it is more a convention than mandatory). Why? Consider below code for binding handler to event.

TestInstance.PublicEvent += (sender, args) => { };

Nothing complicated right? This code just adds lambda function to event. But how exactly? Look at code that is equivalent of above.

EventHandler<TestClass.PublicEventArgs> ha = (sender, args) => { };
TestInstance.PublicEvent += ha.Invoke;

First new object of EventHandler<> type is created with our lambda function as target. After that the same lambda in Invoke method is passed as handler to event. Obviously we need to create object of EventHandler type from Action<object,EventArgs> type. How to do that? Most obvious thing to try is to use constructor of EventHandler<> type.

EventHandler<TestClass.PublicEventArgs> ha = new EventHandler<TestClass.PublicEventArgs>((sender, args) => { });

This works flawlessly. Since we already saw how to use constructors from reflection and expressions it should be easy to create expression that calls constructor retrieved from reflection. Well... not quite.

 

As you can see this type have only one constructor and it involves pointer to some object. Which one? What is happening really, when you create new object of EventHandler type? We can check in CIL code compiled from C#.

IL_0011:  ldsfld      class Delegates.TestEventHandler/'<>c' Delegates.TestEventHandler/'<>c'::'<>9'
IL_0016:  ldftn       instance void Delegates.TestEventHandler/'<>c'::'<.ctor>b__0_0'(object, class Delegates.TestClass/PublicEventArgs)
IL_001c:  newobj    instance void class [mscorlib]System.EventHandler`1<class Delegates.TestClass/PublicEventArgs>::.ctor(object, native int)

Magic happens in ldftn instruction which means: 'Push a pointer to a method referenced by method, on the stack.' according to this page. This means that pointer to method (sender, args) => { } is loaded and with this pointer new EventHandler is created. Because of that we cannot use this constructor because we cannot obtain pointer to a managed method from C#. 

What can we do, then? The simplest solution is to create new method that do this for us. Simple call to new EventHandler() will suffice. We then can use that method in expressions.
Again there is a small problem. As you already know you can't remove event handler if you do not have this handler instance. And you cannot create event instance because you do not know its type. The only thing we can do is to save somewhere relation between user handler (i.e Action<objec, object>) and real EventHandler<EventArgs> handler. Of course it is possible to write EventAdd method, that creates delegate, that returns event handler instance. But it would be somehow unintuitive for end user who expects to work with delegates the same way (or at least as close as possible) as with events. Because of that best idea is to store relations in dictionary in DelegateFactory - it will be transparent for user.

private static readonly Dictionary<WeakReference<object>, WeakReference<object>> EventsProxies =
    new Dictionary<WeakReference<object>, WeakReference<object>>();

Now we can implement EventHandlerFactory method.

public static EventHandler<TEventArgs> EventHandlerFactory<TEventArgs, TSource>(
    object handler, bool isRemove)
    where TEventArgs : class
{
    EventHandler<TEventArgs> newEventHandler;
    var haveKey = false;
    var kv = EventsProxies.FirstOrDefault(k =>
    {
        object keyTarget;
        k.Key.TryGetTarget(out keyTarget);
        if (Equals(keyTarget, handler))
        {
            haveKey = true;
            return true;
        }
        return false;
    });
    if (haveKey)
    {
        object fromCache;
        EventsProxies[kv.Key].TryGetTarget(out fromCache);
        newEventHandler = (EventHandler<TEventArgs>)fromCache;
if (isRemove) { EventsProxies.Remove(kv.Key); return newEventHandler; } } if (!isRemove) { var action = handler as Action<TSource, object>; if (action != null) { newEventHandler = (s, a) => action((TSource)s, a); } else { newEventHandler = new EventHandler<TEventArgs>((Action<object, object>)handler); } EventsProxies[new WeakReference<object>(handler)] = new WeakReference<object>(newEventHandler); return newEventHandler; } return null; }

Idea is really simple. First we are looking for already generated proxy in EventProxies dictionary. If key with reference stored in WeakReference is equal to provided handler we store key-value pair structure and set haveKey variable. We have to use separate bool variable because KeyValuePair type is structure and we cannot perform null check on structure. If key was found we retrieve event handler from target of WeakReference. isRemove parameter is used to differentiate between retrieving/creating event handler for add accessor and remove accessor. For removing event handler we do not need to create it first (because we could not perform removing of handler that way anyway) and if we retrieve saved handler we can remove it from cache at the same time. For add accessor if event handler is not found in cache we can create new one. If provided action handler have first parameter of type different than object we need another lambda proxy with object parameter. It is because events in .NET always have first parameter of object and EventHandler do not accepts different signature. Otherwise we can safely use action directly, passing it to EventHandler constructor. This is why handler parameter have type of object - we need a way to pass different signatures of methods, depending of EventAdd/EventRemove overload. After saving newly created event handler we are done.

Since we are working with incompatible signatures of event handlers and we are writing such complicated factory method in order to create correct ones, we need just one more trick to use it from expressions (and there is no other way). New field in DelegateFactory class will be enough.

private static readonly MethodInfo EventHandlerFactoryMethodInfo = typeof(DelegateFactory).GetMethod("EventHandlerFactory");

This field will be used inside of expressions in similar way as any other MethodInfo object, but after providing type parameters (because it is generic method).

Now we can write new implementation of EventAdd with provided handler with first parameter of source type.

public static Action<TSource, Action<TSource, object>> EventAdd<TSource>(string eventName)
{
    var source = typeof(TSource);
    var eventInfo = GetEventInfo(eventName, source);
    if (eventInfo != null)
    {
        var eventArgsType = eventInfo.EventHandlerType.GetGenericArguments()[0];
        var delegateType = typeof(Action<,>).MakeGenericType(typeof(TSource), typeof(object));
        var instanceParameter = Expression.Parameter(source);
        var delegateTypeParameter = Expression.Parameter(delegateType);
        var methodCallExpression =
            Expression.Call(EventHandlerFactoryMethodInfo.MakeGenericMethod(eventArgsType, source), delegateTypeParameter, Expression.Constant(false));
        var lambda = Expression.Lambda(
                        Expression.Call(instanceParameter, eventInfo.AddMethod, methodCallExpression),
                        instanceParameter, delegateTypeParameter);
        return lambda.Compile() as Action<TSource, Action<TSource, object>>;
    }
    return null;
}

This overload is very similar to previous one, except instead of directly passing delegate to add accessor we instead are passing result of EventHandlerFactory method. To do that we need to obtain event arguments type from eventInfo.EventHandlerType. Both with type of source we create non generic version of method and call it with incompatible handler as parameter and with constant of Boolean.False. This way we will obtain correct handler from cache or from EventHandler constructor. And of course delegateTypeParameter is of object type (since this is type of first parameter in EventHandlerFactory method) instead of EventHandler<>. Resulted delegate will be similar to below lambda.

Action<TestClass, object> d = (i, h) => i.PublicEvent += DelegateFactory.EventHandlerFactory<TestClass.PublicEventArgs,TestClass>(h, false);

Now we can implement last one overload of EventAdd method and much more usable since do not require to know any of types (source type or event arguments type). Working implementation looks like this.

public static Action<object, Action<object, object>> EventAdd(this Type source, string eventName)
{
    var eventInfo = GetEventInfo(eventName, source);
    if (eventInfo != null)
    {
        var eventArgsType = eventInfo.EventHandlerType.GetGenericArguments()[0];
        var instanceParameter = Expression.Parameter(typeof(object));
        var delegateTypeParameter = Expression.Parameter(typeof(object));
        var methodCallExpression =
            Expression.Call(EventHandlerFactoryMethodInfo.MakeGenericMethod(eventArgsType, source), delegateTypeParameter, Expression.Constant(false));
        var lambda = Expression.Lambda(Expression.Call(Expression.Convert(instanceParameter, source),
                                        eventInfo.AddMethod, methodCallExpression),
                        instanceParameter, delegateTypeParameter);
        return lambda.Compile() as Action<object, Action<object, object>>;
    }
    return null;
}

Thing is the same code as before. The only difference is resulting type of delegate. It is because we wrote EventHandlerFactory to support both. Because of that we can create third method with implementation and rewrite previous two.

private static TDelegate EventAddImpl<TDelegate>(this Type source, string eventName)
    where TDelegate : class
{
    var eventInfo = GetEventInfo(eventName, source);
    if (eventInfo != null)
    {
        var eventArgsType = eventInfo.EventHandlerType.GetGenericArguments()[0];
        var instanceParameter = Expression.Parameter(typeof(object));
        var delegateTypeParameter = Expression.Parameter(typeof(object));
        var methodCallExpression =
            Expression.Call(EventHandlerFactoryMethodInfo.MakeGenericMethod(eventArgsType, source), delegateTypeParameter, Expression.Constant(false));
        var lambda = Expression.Lambda(Expression.Call(Expression.Convert(instanceParameter, source),
                                        eventInfo.AddMethod, methodCallExpression),
                        instanceParameter, delegateTypeParameter);
        return lambda.Compile() as TDelegate;
    }
    return null;
}

public static Action<TSource, Action<TSource, object>> EventAdd<TSource>(string eventName)
{
    var source = typeof(TSource);
    return source.EventAddImpl<Action<TSource, Action<TSource, object>>>(eventName);
}

public static Action<object, Action<object, object>> EventAdd(this Type source, string eventName)
{
    return source.EventAddImpl<Action<object, Action<object, object>>>(eventName);
}

This is what we need to create delegates for add accessors in different situations. Now we can test them, to make sure if everything is working fine. EventAdd overloads should be called in following way.

var ea1 = DelegateFactory.EventAdd<TestClass, TestClass.PublicEventArgs>("PublicEvent");
var ea2 = DelegateFactory.EventAdd<TestClass, TestClass.InternalEventArgs>("InternalEvent");
var ea3 = DelegateFactory.EventAdd<TestClass>("ProtectedEvent");
var ea4 = Type.EventAdd<TestClass.PublicEventArgs>("PublicEvent");
var ea5 = Type.EventAdd("PrivateEvent");

To test if this delegates works we need to create few handlers.

private static void HandlerWithoutSourceType(object o, TestClass.PublicEventArgs eventArgs)
{
    Console.WriteLine("Public handler without source type works!");
}

private static void HandlerWithSourceType(TestClass sender, object eventArgs)
{
    if (eventArgs.GetType() ==
        Type.GetNestedType("ProtectedEventArgs", BindingFlags.Instance | BindingFlags.NonPublic))
    {
        Console.WriteLine("Protected handler works!");
    }
}

private static void TypelessHandler(object sender, object eventArgs)
{
    if (eventArgs is TestClass.PublicEventArgs)
    {
        Console.WriteLine("Public handler works!");
    }
    else if (eventArgs is TestClass.InternalEventArgs)
    {
        Console.WriteLine("Internal handler works!");
    }
    else if (eventArgs.GetType() ==
        Type.GetNestedType("PrivateEventArgs", BindingFlags.Instance | BindingFlags.NonPublic))
    {
        Console.WriteLine("Private handler works!");
    }
}

Now we can bind handlers to events using delegates.

ea1(TestInstance, TypelessHandler);
ea2(TestInstance, TypelessHandler);
ea3(TestInstance, HandlerWithSourceType);
ea4(TestInstance, HandlerWithoutSourceType);
ea5(TestInstance, TypelessHandler);

This is why handler methods have different set of texts to write in a console - not everyone handles all of events.

TestInstance.InvokePublicEvent();
TestInstance.InvokeInternalEvent();
TestInstance.InvokeProtectedEvent();
TestInstance.InvokePrivateEvent();

After invoking events by special public methods above we will see output in a console like below.

Public handler works!
Public handler without source type works!
Internal handler works!
Protected handler works!
Private handler works!

It means that every event handler works, despite different visibility, different signatures of user handlers, custom and default accessors.

 

Event remove accessors

Best thing about remove accessors are that there have the same signatures as add accessors. Main problems with remove accessors, which is the need for exactly the same reference, is handled in EventHandlerFactory method. In EventRemove methods we just need to change eventInfo.AddMethod to eventInfo.RemoveMethod and pass Boolean.True instead ofBoolean.False to EventHandlerFacory method (to remove unecessary instances of EventHandler from dictionary).

public static Action<TSource, EventHandler<TEventArgs>> EventRemove<TSource, TEventArgs>(string eventName)
{
    var source = typeof(TSource);
    var eventInfo = GetEventInfo(eventName, source);
    return (Action<TSource, EventHandler<TEvent>>)
            eventInfo?.RemoveMethod.CreateDelegate(typeof(Action<TSource, EventHandler<TEvent>>));
}

public static Action<object, EventHandler<TEventArgs>> EventRemove<TEventArgs>(
    this Type source, string eventName)
{
    var eventInfo = GetEventInfo(eventName, source);
    if (eventInfo != null)
    {
        var instanceParameter = Expression.Parameter(typeof(object));
        var delegateTypeParameter = Expression.Parameter(typeof(EventHandler<TEventArgs>));
        var lambda = Expression.Lambda(Expression.Call(Expression.Convert(instanceParameter, source),
                                        eventInfo.RemoveMethod, delegateTypeParameter),
                        instanceParameter, delegateTypeParameter);
        return (Action<object, EventHandler<TEventArgs>>)lambda.Compile();
    }
    return null;
}

public static Action<TSource, Action<TSource, object>> EventRemove<TSource>(string eventName)
{
    return typeof(TSource).EventRemoveImpl<Action<TSource, Action<TSource, object>>>(eventName);
}

public static Action<object, Action<object, object>> EventRemove(this Type source, string eventName)
{
    return source.EventRemoveImpl<Action<object, Action<object, object>>>(eventName);
}

private static TDelegate EventRemoveImpl<TDelegate>(this Type source, string eventName) where TDelegate : class { var eventInfo = GetEventInfo(eventName, source); if (eventInfo != null) { var eventArgsType = eventInfo.EventHandlerType.GetGenericArguments()[0]; var instanceParameter = Expression.Parameter(typeof(object)); var delegateTypeParameter = Expression.Parameter(typeof(object)); var methodCallExpression = Expression.Call(EventHandlerFactoryMethodInfo.MakeGenericMethod(eventArgsType, source), delegateTypeParameter, Expression.Constant(true)); var lambda = Expression.Lambda(Expression.Call(Expression.Convert(instanceParameter, source), eventInfo.RemoveMethod, methodCallExpression), instanceParameter, delegateTypeParameter); return lambda.Compile() as TDelegate; } return null; }

Code is almost the same. Because of that we can rewrite all those method to build delegate for selected accessor. We just need two constants and extra code for selection of correct accessor MethodInfo.

private const string AddAccessor = "add";
private const string RemoveAccessor = "remove";

public static Action<object, EventHandler<TEventArgs>> EventRemove<TEventArgs>( this Type source, string eventName) { return EventAccessor<TEventArgs>(source, eventName, RemoveAccessor); } public static Action<TSource, EventHandler<TEventArgs>> EventRemove<TSource, TEventArgs>(string eventName) { return EventAccessor<TSource, TEventArgs>(eventName, RemoveAccessor); } public static Action<TSource, Action<TSource, object>> EventRemove<TSource>(string eventName) { return typeof(TSource).EventRemoveImpl<Action<TSource, Action<TSource, object>>>(eventName); } public static Action<object, Action<object, object>> EventRemove(this Type source, string eventName) { return source.EventRemoveImpl<Action<object, Action<object, object>>>(eventName); }

Methods with logic will contain all of previously discussed code.

private static Action<object, EventHandler<TEventArgs>> EventAccessor<TEventArgs>
    (Type source, string eventName, string accessorName)
{
    var accessor = GetEventInfoAccessor(eventName, source, accessorName);
    if (accessor != null)
    {
        var instanceParameter = Expression.Parameter(typeof(object));
        var delegateTypeParameter = Expression.Parameter(typeof(EventHandler<TEventArgs>));
        var lambda = Expression.Lambda(Expression.Call(Expression.Convert(instanceParameter, source),
            accessor, delegateTypeParameter),
            instanceParameter, delegateTypeParameter);
        return (Action<object, EventHandler<TEventArgs>>)lambda.Compile();
    }
    return null;
}

private static Action<TSource, EventHandler<TEventArgs>> EventAccessor<TSource, TEventArgs>
    (string eventName, string accessorName)
{
    var sourceType = typeof(TSource);
    var accessor = GetEventInfoAccessor(eventName, sourceType, accessorName);
    return (Action<TSource, EventHandler<TEventArgs>>)
        accessor?.CreateDelegate(typeof(Action<TSource, EventHandler<TEventArgs>>));
}

private static TDelegate EventAccessorImpl<TDelegate>(Type source, string eventName, string accessorName)
    where TDelegate : class
{
    var eventInfo = GetEventInfo(eventName, source);
    if (eventInfo != null)
    {
        var accessor = accessorName == AddAccessor ? eventInfo.AddMethod : eventInfo.RemoveMethod;
        var eventArgsType = eventInfo.EventHandlerType.GetGenericArguments()[0];
        var instanceParameter = Expression.Parameter(typeof(object));
        var delegateTypeParameter = Expression.Parameter(typeof(object));
        var methodCallExpression =
            Expression.Call(EventHandlerFactoryMethodInfo.MakeGenericMethod(eventArgsType, source),
                delegateTypeParameter, Expression.Constant(accessorName == RemoveAccessor));
        var lambda = Expression.Lambda(Expression.Call(Expression.Convert(instanceParameter, source),
            accessor, methodCallExpression),
            instanceParameter, delegateTypeParameter);
        return lambda.Compile() as TDelegate;
    }
    return null;
}

private static TDelegate EventRemoveImpl<TDelegate>(this Type source, string eventName)
    where TDelegate : class
{
    return EventAccessorImpl<TDelegate>(source, eventName, RemoveAccessor);
}

Ok. Biggest difference is obtaining accessors. New method for that looks like below.

private static MethodInfo GetEventInfoAccessor(string eventName, Type sourceType, string accessor)
{
    var eventInfo = GetEventInfo(eventName, sourceType);
    return accessor == AddAccessor ? eventInfo?.AddMethod : eventInfo?.RemoveMethod;
}

Beside obtaining accessor in EventAccessorImpl method, worth to mention is code for setting flag for EventHandlerFactory.

To test if delegates works we can use them and then raise events - if removing of events works we will not see anything in console. To obtain delegates we can execute following lines.

var er1 = DelegateFactory.EventRemove<TestClass, TestClass.PublicEventArgs>("PublicEvent");
var er2 = DelegateFactory.EventRemove<TestClass, TestClass.InternalEventArgs>("InternalEvent");
var er3 = DelegateFactory.EventRemove<TestClass>("ProtectedEvent");
var er4 = Type.EventRemove<TestClass.PublicEventArgs>("PublicEvent");
var er5 = Type.EventRemove("PrivateEvent");

Calling newly created delegates after previous ones (for add accessors) should remove handlers.

er1(TestInstance, TypelessHandler);
er2(TestInstance, TypelessHandler);
er3(TestInstance, HandlerWithSourceType);
er4(TestInstance, HandlerWithoutSourceType);
er5(TestInstance, TypelessHandler);

TestInstance.InvokePublicEvent();
TestInstance.InvokeInternalEvent();
TestInstance.InvokeProtectedEvent();
TestInstance.InvokePrivateEvent();

Calling above lines right after test code for add accessors will cause to output test texts in console only one time. It means it works. Everything is fine. Smile

 

Summary

In this article we covered how and why create delegates for generic methods (static and instance) and events. Along with previous two articles we covered all members, and now have fast way to access all them without caring for visibility or performance of reflection.

Code for this article and previous ones can be found on github.



Faster than Reflection: Delegates. Part 2.

clock August 16, 2016 08:59 by author n.podbielski

This is second article in series, that explains how to create delegates for public and non-public members of public, non-public or not known in compile-time types. If you are not familiar with previous article and looking for detailed explanation of how delegates works, how they are created and why, I strongly encourage you to read it first. If you are just looking for a way to create delegates for methods or constructors it is not necessary.

In previous article and first one in series, we covered:

  1. Static
    1. Properties
    2. Fields
  2. Instance
    1. Properties
    2. Fields
    3. Indexers

Now it is time to cover following members.

  1. Static
    1. Methods
  2. Instance
    1. Methods
    2. Constructors

 

First members we will discuss are constructors.

 

Constructors

Of course we are talking about non-static constructors. Yes the static ones also exists, but they are special way of initialization of types not objects. They are called automatically on first use of type and we do not need to do that ourselves and we certainly do not need delegates for that.

Any type can have any number of constructors, so first thing we need is way to indicate which one we need to call by delegate. Since constructors can differ by parameters types, we can do this in similar way as with indexers - set of types for parameters that indicates clearly, which one it should be. Of course very often types do not have any special constructor (declared by user). For this cases we will look for default constructor without parameters. Since this is less complex we can discuss first.

What we need to start? Since every type have at least one constructor even if is not added by the user we do not need to add anything to our TestClass. But as before with other members we had to add separate method to obtain constructors by reflection.

private static ConstructorInfo GetConstructorInfo(Type source, Type[] types)
{
    return (source.GetConstructor(BindingFlags.Public, null, types, null) ??
              source.GetConstructor(BindingFlags.NonPublic, null, types, null)) ??
              source.GetConstructor(
                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null,
                types, null);
}

Above code is explained in details in previous article and for other type of member. Quick explanation: it looks for public, then private and protected and last internal constructors.

Now we can implement method, that will create delegates for constructors. This new method in DelegateFactory will be called DefaultConstructor.

public static Func<TSource> DefaultContructor<TSource>()
{
    var source = typeof(TSource);
    var constructorInfo = GetConstructorInfo(source, Type.EmptyTypes);
    if (constructorInfo == null)
    {
        return null;
    }
    return (Func<TSource>)Expression.Lambda(Expression.New(constructorInfo)).Compile();
}

As you can see it is very similar to PropertyGet from previous article. First constructor is obtained from and then after null check is passed to Expression.New method that creates expression that call this constructor. After that, value is returned.

Above method should be called in following way.

var dc = DelegateFactory.DefaultContructor<TestClass>();
var instance = dc();

It works like any other method, that do not take parameters and returns value, which is our new instance.

How about case when we do not have access to type this way? We can write extension method that returns an object.

public static Func<object> DefaultContructor(this Type source)
{
    var constructorInfo = GetConstructorInfo(source, Type.EmptyTypes);
    if (constructorInfo == null)
    {
        return null;
    }
    return (Func<object>)Expression.Lambda(Expression.New(constructorInfo)).Compile();
}

var dc3 = Type.DefaultContructor()

Produced delegate is called exactly the same way. In case you are wondering why there is no casting return value to object, if source type is not class (like in PropertyGet) it is because structures cannot have parameterless constructors. You can easily test it by getting list of i.e. int - no constructors returned by reflection.

Both above methods creates delegates that can be converted to following lambda.

Func<TestClass> d = () => new TestClass();

Now we should target more complicated constructors with parameters. Let us create few test constructors in TestClass.

internal TestClass(int p)
    : this()
{
}

protected TestClass(bool p)
    : this()
{
}

private TestClass(string p)
    : this()
{
}

Ideally would be to call new overload with source type parameter (or parameter with type) and list of types parameters for constructor parameters.

Func<int,TestClass> c = DelegateFactory.Contructor<TestClass, int>>();

Problem with this is that C# is not C++ and you cannot have class that takes unspecified number of type parameters. So either we can create separate overload for every number of parameters (up to limit of Func class) or write a little less convenient overload but more universal.

var c = DelegateFactory.Contructor<TestClass, Func<int, TestClass>>();

Resulted variable is the same. In previous example we could also write var keyword instead of explicit type of delegate but it would be less readable, why we cannot do that. Difference between first and second version is that in second we have explicit return type passed to overload (it is not created from generic method). How we can obtain types of parameters then? It is very easy with reflection.

private static Type[] GetFuncDelegateArguments<TDelegate>() where TDelegate : class
{
    return typeof(TDelegate).GenericTypeArguments.Reverse().Skip(1).Reverse().ToArray();
}

Above function retrieves parameters from delegates created by Func class. Reversing and skipping of one type parameter is performed to omit last one, which is always return type. For above exemplary calls (Func<TestClass,int>) it will return {typeof(int)}, array with single element - type of integral number, Int32.

If you look close enough you can notice, that TestClass type parameter in our designed Constructor overload is passed twice: on its own and as return type of constructor overload. It is not necessary and we can remove first type parameter by obtaining source type of constructor from delegate. It can be very easily done by method as below.

private static Type GetFuncDelegateReturnType<TDelegate>() where TDelegate : class
{
    return typeof(TDelegate).GenericTypeArguments.Last();
}

Now we can implement first overload for constructors with parameters.

public static TDelegate Contructor<TDelegate>() where TDelegate : class
{
    var source = GetFuncDelegateReturnType<TDelegate>();
    var ctrArgs = GetFuncDelegateArguments<TDelegate>();
    var constructorInfo = GetConstructorInfo(source, ctrArgs);
    if (constructorInfo == null)
    {
        return null;
    }
    var parameters = ctrArgs.Select(Expression.Parameter).ToList();
    return Expression.Lambda(Expression.New(constructorInfo, parameters), parameters).Compile() as TDelegate;
}

Obviously set of type parameters in TDelegate type have to be correct for this to work, but it is exactly the same when you use reflection - you have to pass correct types to obtain MethodInfo and then correct parameters to call method.

For example for TestClass constructor with int parameter this method would create delegate, that can be represented by below lambda.

Func<int, TestClass> d = i => new TestClass(i);

Main difference from DefaultContructor method is set of parameters in both: Expression.New and Expression.Lambda calls, created from array of types passed in TDelegate as type arguments.

Good thing about that mechanism is, that it will work as well for parameterless constructor and we can use this method to rewrite DefaultContructor method.

public static Func<TSource> DefaultContructor<TSource>()
{
    return Contructor<Func<TSource>>();
}

This method should return delegate without parameters that returns instance, so Func<TSource> is passed. But how about a case when we do not know type and we want delegate for constructor with parameters? We have to change Constructor method so it returns delegate with return type of object. Because of that we can't acquire source type from delegate so we have to pass it differently.

public static TDelegate Contructor<TDelegate>(this Type source)
    where TDelegate : class
{
    var ctrArgs = GetFuncDelegateArguments<TDelegate>();
    var constructorInfo = GetConstructorInfo(source, ctrArgs);
    if (constructorInfo == null)
    {
        return null;
    }
    var parameters = ctrArgs.Select(Expression.Parameter).ToList();
    Expression returnExpression = Expression.New(constructorInfo, parameters);
    if (!source.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return Expression.Lambda(returnExpression, parameters).Compile() as TDelegate;
}

There are few points that might need to be clarified. It almost the same as previous one but it do returns object instead of source type. If type to construct is structure it is converted to object before returning final value. Safe cast at the end forces user to pass matching delegate.

If we would write structure like this:

public struct TestStruct
{
    public TestStruct(int i)
    {

    }
}

Above method called would produce delegate very similar to the one below.

var c = typeof(TestStruct).Contructor<Func<int, object>>();
Func<int, object> d = i => (object)new TestStruct(i);

Next problem arise when we do not have access to all types of parameters - not known type method can have parameters that are also unknown. This is similar problem to the one, that forced us to create Constructor<TDelegate> overload - we cannot really know what type of delegate should be constructed if we do not know types of arguments. Of course we could create method that returns delegate with correct number of parameters as in constructor, but with not known types changed to object. But it stills limits us to number of parameters allowed in Func class (however if code have methods with that number of parameters there are probably more pressure problems than this Smile) and it could return constructor different than expected (there can be more than one with given number of parameters). So instead we should write more general method that takes array of types for constructor, exactly how this was done with indexers in previous article.

public static Func<object[], object> Contructor(this Type source, params Type[] ctrArgs)
{
    var constructorInfo = GetConstructorInfo(source, ctrArgs);
    if (constructorInfo == null)
    {
        return null;
    }
    var argsArray = Expression.Parameter(typeof(object[]));
    var paramsExpression = new Expression[ctrArgs.Length];
    for (var i = 0; i < ctrArgs.Length; i++)
    {
        var argType = ctrArgs[i];
        paramsExpression[i] = 
            Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType);
    }
    Expression returnExpression = Expression.New(constructorInfo, paramsExpression);
    if (!source.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return (Func<object[], object>)Expression.Lambda(returnExpression, argsArray).Compile();
}

It returns delegate that takes array of objects and returns object. Objects are cast to correct type of parameter at the same index. Collections of cast parameters is collection of arguments for constructor. Created instance is then converted to object if is of value type. This will look much clearer as lambda for constructor with single parameter.

Func<object[], object> d = args => (object)new TestStruct((int)args[0]);

We should test those methods now. Below lines creates delegates and then creates instances by those delegates.

var cd = DelegateFactory.DefaultContructor<TestClass>();
var cd1 = Type.DefaultContructor();
var cd2 = Type.Contructor<Func<object>>();

var t_ = cd();
var t1 = cd1();
var t2 = cd2();

var c1 = DelegateFactory.Contructor<Func<TestClass>>();
var c2 = DelegateFactory.Contructor<Func<int, TestClass>>();
var c3 = DelegateFactory.Contructor<Func<bool, TestClass>>();
var c4 = DelegateFactory.Contructor<Func<string, TestClass>>();
var c5 = DelegateFactory.Contructor<Func<int, TestClass>>();
var c6 = Type.Contructor(typeof(int));
var c7 = typeof(TestStruct).Contructor<Func<int, object>>();
var c8 = typeof(TestStruct).Contructor(typeof(int));

var t3 = c1();
var t4 = c2(0);
var t5 = c3(false);
var t6 = c4("");
var t7 = c5(0);
var t8 = c6(new object[] { 0 });
var t9 = c7(0);
var t10 = c8(new object[] { 0 });

If you are wondering what is Type variable above - it is instance of TestClass, which is class for testing all of delegates. Both are explained in previous article in series. You can also look for a code for this article (and previous one) on github.

All variables with names starting with 't' will have value of newly created instance. It is very nice because constructors called via delegates c1, c2, c3 and c4, have different visibility (public, internal, protected and private) and all works without problems. It works but how fast is it?

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = new TestClass();
}
_stopWatch.Stop();
Console.WriteLine("Public default constructor directly: {0}", _stopWatch.ElapsedMilliseconds);

var constructorInfo = Type.GetConstructor(Type.EmptyTypes);
_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = (TestClass)constructorInfo.Invoke(null);
}
_stopWatch.Stop();
Console.WriteLine("Public default constructor via reflection: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = Activator.CreateInstance();
}
_stopWatch.Stop();
Console.WriteLine("Public default constructor via Activator: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var t = c1();
}
_stopWatch.Stop();
Console.WriteLine("Public default constructor proxy: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = c5(0);
}
_stopWatch.Stop();
Console.WriteLine("Public constructor with parameter proxy: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    c6(new object[] {0});
}
_stopWatch.Stop();
Console.WriteLine("Public constructor with parameter via array proxy: {0}", _stopWatch.ElapsedMilliseconds);

After running we will see results like below.

Public default constructor directly: 14896
Public default constructor via reflection: 33763
Public default constructor via Activator: 21690
Public default constructor proxy: 14923
Public constructor with parameter proxy: 15261
Public constructor with parameter via array proxy: 16768

As you can see difference is very small between calling default constructor directly and by delegate. It is because it is call to the same method without any intermediate call. Activator is significantly slower, which is expected since code in Activator class searches for correct constructor in type (by given parameters to CreateInstance method) and then calls it. It takes times if it is done so many times. Reflection is more than two times slower. Last two delegates are little slower, but not so much (3-12%). Difference would be bigger with empty or less complicated constructor (TestClass constructor have initialization of fields and properties), but even then it involves less calculation (in comparison to the reflection or Activator) with just few casts and indexing operations.

Now when we have constructors covered we can switch to even more important member type: methods.

 

Static methods

After the the properties covered in first article, it is time for methods, which are also one of the most usable type of members. With experienced gained dealing with constructors, methods should not be a problem Smile. Static ones first.

Main difference between static methods and constructors is, that constructors have fixed return type, which is the same as source type. With static methods we have to be more flexible, so we need one extra parameter for all delegate-creation methods. Similar to constructors we will write three overloads for static methods: static method with source type in type parameter, type extension method with Type of delegate in type parameter, and Type extension method with list of parameters type of our desired static method overload (if there are more than one with the same name). It will be much clearer in form of a code.

var sm1 = DelegateFactory.StaticMethod<TestClass, Func<string, string>>("StaticPrivateMethod");
var sm2 = Type.StaticMethod<Func<string, string>>("StaticPublicMethod");
var sm3 = Type.StaticMethod("StaticPublicMethod", typeof(string));

Those three overloads should cover all cases: when we know all types (source class type, parameters types, and return method type), when we do not know source type, but we know parameters types, and when we do not know any types.

There is one complication (comparing to constructor): methods, static and instance, do not have to have return type (or to be more precise return type is equal to typeof(void)). So first and second overload should work also with Action delegates.

var sm1 = DelegateFactory.StaticMethod<TestClass, Action<string, string>>("StaticPublicMethod");
var sm2 = Type.StaticMethod<Action<string, string>>("StaticPublicMethod");

With third overload it is more complex case. It would be awesome if it would produce different delegate (Action or Func) if static method is void or not. It is possible, but would not be very convenient. Look at following code.

var sm1 = (Action<object[]>)Type.StaticMethod("StaticPublicMethod", typeof(string));
var sm2 = (Func<object[], object>)Type.StaticMethod("StaticPublicMethod", typeof(string));

To make produced delegate possible to invoke, we would have to cast it to correct type, so embedding information about type of delegate into code is necessary anyway. Thing is, to use any static method of any class we have to be aware of its signature anyway to be able to write code that will work with this method. So it is much more convenient to write two separate methods for creating static method delegate when we do not know types of source and parameters (at compile-time).

var sm1 = Type.StaticMethod("StaticPublicMethod", typeof(string));
var sm2 = Type.StaticMethodVoid("StaticPublicMethodVoid", typeof(string));

First delegate is for Func and second is for Action delegate. If user of DelegateFactory have to be aware of static method signature, this way it is much more convenient to use.

Before implementing above functions we have to write a method for obtaining static methods MethodInfo object, just like in constructors.

private static MethodInfo GetStaticMethodInfo(Type source, string name, Type[] types)
{
    var methodInfo = (source.GetMethod(name, BindingFlags.Static, null, types, null) ??
                               source.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic, null, types, null)) ??
                               source.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, types, null);
    return methodInfo;
}

Very similar code. We are looking for method with specified name with flags set to static member and different visibility of a method.

Now we can implement StaticMethod overloads.

public static TDelegate StaticMethod<TSource, TDelegate>(string name)
    where TDelegate : class
{
    return typeof(TSource).StaticMethod<TDelegate>(name);
}

public static TDelegate StaticMethod<TDelegate>(this Type source,
    string name)
    where TDelegate : class
{

    var paramsTypes = GetFuncDelegateArguments<TDelegate>();
    var methodInfo = GetStaticMethodInfo(source, name, paramsTypes);
    return methodInfo.CreateDelegate(typeof(TDelegate)) as TDelegate;
}

Nothing complicated here. Just delegate creation from MethodInfo object, like in properties, indexers and constructors. First overload is just call to second one. Of course TDelegate have to be compatible with static method signature. The same is required if you want to call method by reflection.

If we add new test method to TestClass, delegates created by above methods would be also be product of following lambda statement for TestClass.

public static string StaticPublicMethod(string s)
{
    return s;
}

Func<string, string> d = s1 => TestClass.StaticPublicMethod(s1);

Third overload in form of StaticMethod and StaticMethodVoid is a little more complicated and, as constructor called by objects in this article and other members in previous one, it requires expressions.

public static Func<object[], object> StaticMethod(this Type source,
    string name, params Type[] paramsTypes)
{
    var methodInfo = GetStaticMethodInfo(source, name, paramsTypes);
    var argsArray = Expression.Parameter(typeof(object[]));
    var paramsExpression = new Expression[paramsTypes.Length];
    for (var i = 0; i < paramsTypes.Length; i++)
    {
        var argType = paramsTypes[i];
        paramsExpression[i] =
            Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType);
    }
    Expression returnExpression = Expression.Call(methodInfo, paramsExpression);
    if (!source.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return (Func<object[], object>)Expression.Lambda(returnExpression, argsArray).Compile();
}

public static Action<object[]> StaticMethodVoid(this Type source,
    string name, params Type[] paramsTypes)
{
    var methodInfo = GetStaticMethodInfo(source, name, paramsTypes);
    var argsArray = Expression.Parameter(typeof(object[]));
    var paramsExpression = new Expression[paramsTypes.Length];
    for (var i = 0; i < paramsTypes.Length; i++)
    {
        var argType = paramsTypes[i];
        paramsExpression[i] =
            Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType);
    }
    Expression returnExpression = Expression.Call(methodInfo, paramsExpression);
    return (Action<object[]>)Expression.Lambda(returnExpression, argsArray).Compile();
}

If you are wondering if those methods can be rewritten to share code, you are right. They can and without loss of performance like with property setters. We can check if return type of method is void and omit casting to object and set final delegate type as type parameter.

public static Func<object[], object> StaticMethod(this Type source,
    string name, params Type[] paramsTypes)
{
    return StaticMethod<Func<object[], object>>(source, name, paramsTypes);
}

public static Action<object[]> StaticMethodVoid(this Type source,
    string name, params Type[] paramsTypes)
{
    return StaticMethod<Action<object[]>>(source, name, paramsTypes);
}

public static TDelegate StaticMethod<TDelegate>(this Type source,
    string name, params Type[] paramsTypes)
    where TDelegate : class
{
    var methodInfo = GetStaticMethodInfo(source, name, paramsTypes);
    var argsArray = Expression.Parameter(typeof(object[]));
    var paramsExpression = new Expression[paramsTypes.Length];
    for (var i = 0; i < paramsTypes.Length; i++)
    {
        var argType = paramsTypes[i];
        paramsExpression[i] =
            Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType);
    }
    Expression returnExpression = Expression.Call(methodInfo, paramsExpression);
    if (methodInfo.ReturnType != typeof(void) && !methodInfo.ReturnType.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return Expression.Lambda(returnExpression, argsArray).Compile() as TDelegate;
}

We should create few new methods in TestClass to be able to test if everything works fine.

public static string StaticPublicMethod(int i)
{
    return i.ToString();
}

public static string StaticPublicMethodVoidParameter;

public static void StaticPublicMethodVoid(string s)
{
    StaticPublicMethodVoidParameter = s;
}

internal static string StaticInternalMethod(string s)
{
    return s;
}

protected static string StaticProtectedMethod(string s)
{
    return s;
}

private static string StaticPrivateMethod(string s)
{
    return s;
}

For StaticPublicMethod and StaticPublicMethodVoid created delegates can be represented by lambdas like below.

Func<object[], object> d1 = os => TestClass.StaticPublicMethod((string)os[0]);
Action<object[]> d2 = os => TestClass.StaticPublicMethodVoid((string)os[0]);

If return type of StaticPublicMethod would be value type cast to object of lambda return value would be added.

Now we can test if everything works in console application. Let us add few lines to Main method of program.

var sm1 = DelegateFactory.StaticMethod<TestClass, Func<string, string>>("StaticPublicMethod");
var sm2 = DelegateFactory.StaticMethod<TestClass, Func<string, string>>("StaticInternalMethod");
var sm3 = DelegateFactory.StaticMethod<TestClass, Func<string, string>>("StaticProtectedMethod");
var sm4 = DelegateFactory.StaticMethod<TestClass, Func<string, string>>("StaticPrivateMethod");
var sm5 = Type.StaticMethod<Func<string, string>>("StaticPublicMethod");
var sm6 = Type.StaticMethod<Func<string, string>>("StaticInternalMethod");
var sm7 = Type.StaticMethod<Func<string, string>>("StaticProtectedMethod");
var sm8 = Type.StaticMethod<Func<string, string>>("StaticPrivateMethod");
var sm9 = Type.StaticMethod("StaticPublicMethod", typeof(string));
var sm10 = Type.StaticMethodVoid("StaticPublicMethodVoid", typeof(string));
var sm11 = Type.StaticMethod("StaticInternalMethod", typeof(string));
var sm12 = Type.StaticMethod("StaticProtectedMethod", typeof(string));
var sm13 = Type.StaticMethod("StaticPrivateMethod", typeof(string));
var sm14 = DelegateFactory.StaticMethod<TestClass, Func<int, int>>("StaticPublicMethodValue");
var sm15 = Type.StaticMethod<Func<int, int>>("StaticPublicMethodValue");
var sm16 = Type.StaticMethod("StaticPublicMethodValue", typeof(int));
            
var t = sm1("test");
var t2 = sm2("test");
var t3 = sm3("test");
var t4 = sm4("test");
var t5 = sm5("test");
var t6 = sm6("test");
var t7 = sm7("test");
var t8 = sm8("test");
var t9 = sm9(new object[] { "test" });
sm10(new object[] { "test" });
var t10 = TestClass.StaticPublicMethodVoidParameter;
var t11 = sm11(new object[] { "test" });
var t12 = sm12(new object[] { "test" });
var t13 = sm13(new object[] { "test" });
var t14 = sm14(0);
var t15 = sm15(0);
var t16 = sm16(new object[] { 0 });

Lots of lines with really simple logic behind them. Four first lines creates delegates by overload of StaticMethod method with parameter types, so created delegates have full knowledge of methods signature. Next four lines produces delegates using source type from Type instance - also signatures of static methods are retained. After that we have two lines that takes set of parameter types, and creates delegates that have single parameter no matter of number of parameters of method called by delegate, but they differs by return type of created delegate (void or object). Next three works the same way but for non-public methods. Last three test all StaticMethod overloads, but for source method that returns value type instead of reference type. Second part of above test just calls created delegates.

 

Returned values are what there are supposed to be, judging by definition of static methods in TestClass.

Last thing to do about static methods is too test performance of delegates.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = TestClass.StaticPublicMethod("test");
}
_stopWatch.Stop();
Console.WriteLine("Static Public method directly: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = sm1("test");
}
_stopWatch.Stop();
Console.WriteLine("Static Public method proxy: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = sm9(new object[] { "test" });
}
_stopWatch.Stop();
Console.WriteLine("Static Public method via proxy with array: {0}", _stopWatch.ElapsedMilliseconds);

var methodInfo = Type.GetMethod("StaticPublicMethod", new[] { typeof(string) });
_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = methodInfo.Invoke(null, new object[] { "test" });
}
_stopWatch.Stop();
Console.WriteLine("Static Public method via reflection: {0}", _stopWatch.ElapsedMilliseconds);

Result in console application will again prove that delegates are much faster than reflection.

Static Public method directly: 1160
Static Public method proxy: 1167
Static Public method via proxy with array: 2930
Static Public method via reflection: 21317

As you can see calling method by delegate is just a little slower. More thorough tests shows that it may varied depending on method signature and body, but still it should be slower only by few percent. Calls by array of object is obviously slower because of all the casting and indexing; in above example it takes 2.5 times longer, but it would be most probably less with more complicated method than just return statement. Last line shows that reflection is much more slower, as expected (about 18 times).

Last thing to do is to add check for null if methodInfo variable is null to prevent errors. It works the same as with constructors: null propagation operator ? for overload with only reflection and if statement for overload with expressions.

Now we can jump to instance methods.

 

Instance methods

Instance methods will have very similar overloads except for StaticMethod<TSource, TDelegate>(string name), which is just not necessary since with instance methods we can obtain TSource from first parameter of TDelegate. The same was with properties. Instance methods are like static methods that takes first parameter with instance, which have meaning of this keyword inside method body. Easiest way to understand it is to think of instance method as extension methods. For example for test method like below:

public string PublicMethod(string s)
{
    return s;
}

we will create delegate that could look like following static extension method.

public string Delegate(this TestClass @this, string s)
{
    return @this.PrivateMethod(s);
}

It works the same like instance properties, fields and indexers in previous article.

Ok, let us implements overloads of InstanceMethod methods. First will be the one with all known types (source type, parameters and return type).

public static TDelegate InstanceMethod<TDelegate>(string name)
    where TDelegate : class
{
    var paramsTypes = GetFuncDelegateArguments<TDelegate>();
    var source = paramsTypes.First();
    paramsTypes = paramsTypes.Skip(1).ToArray();
    var methodInfo = GetMethodInfo(source, name, paramsTypes);
    return methodInfo?.CreateDelegate(typeof(TDelegate)) as TDelegate;
}

Since we know all types, we also have to know signature of method and this signature is passed as TDelegate type to InstanceMethod method. Consider PublicMethod mentioned above. For this method TDelegate should look like below.

Func<TestClass, string, string>

It is method that takes two parameters (instance. on which method should be called and this method parameter) and returns string. Rest of overload code of InstanceMethod is very similar to Constructor method. We take parameters from TDelegate, takes first one which is source type and takes rest to search for correct overload of method in source type. After that delegate is created like before with other members types. Example call to this overload should look like this.

var m1 = DelegateFactory.InstanceMethod<Func<TestClass, string, string>>("PublicMethod");

With other members types we always discussed overload when we do not want to pass source type as type parameter, but instead we pass it as first parameter of extension method. Thing is with instance methods we have the same problem as with constructors: we cannot create overload that takes unspecified number of type parameters and in return creates delegate with unspecified number of parameters. It forces us to pass delegate type or write separate method for every number of parameters. Passing delegate causes source type to be specified twice. If we want to write similar extension method, like with other members, we should allow delegate with first parameter as object instead of source type. This makes things a little more complicated (and I do not think it will be very useful, but it will make DelegateFactory more concise).

public static TDelegate InstanceMethod<TDelegate>(this Type source, string name)
    where TDelegate : class
{
    var delegateParams = GetFuncDelegateArguments<TDelegate>(true);
    var methodInfo = GetMethodInfo(source, name, delegateParams);
    if (methodInfo == null)
    {
        return null;
    }
    Delegate deleg;
    if (delegateParams[0] == source)
    {
        deleg = methodInfo.CreateDelegate(typeof(TDelegate));
    }
    else
    {
        var sourceParameter = Expression.Parameter(typeof(object));
        var expressions = delegateParams.Select(Expression.Parameter).ToArray();
        Expression returnExpression = Expression.Call(Expression.Convert(sourceParameter, source),
            methodInfo, expressions.Cast<Expression>());
        if (methodInfo.ReturnType != typeof(void) && !methodInfo.ReturnType.IsClass)
        {
            returnExpression = Expression.Convert(returnExpression, typeof(object));
        }
        var lamdaParams = new[] { sourceParameter }.Concat(expressions);
        deleg = Expression.Lambda(returnExpression, lamdaParams).Compile();
    }
    return deleg as TDelegate;
}

It is a lot of code, but is not that much complicated. If delegate first parameter, which can be source instance or object (or any compatible type), is equal source parameter it works exactly as previous overload. If not it performs delegate creation via expression very similar to similar Constructor overload. List of parameters types returned from TDelegate is used to create ExpressionsParameter collection to Expression.Call. The same collection with source parameter (as object) is used as parameters set for Expression.Lambda. If statement casts return expression to object if value to returns is structure and only if method do not return void.

For TestClass.PublicMethod method above overload will create delegate similar to below lambdas.

Func<TestClass, string, string> d1 = (i, s) => i.PublicMethod(s);
Func<object, string, string> d2 = (i, s) => ((TestClass)i).PublicMethod(s);

Two versions depending if we call it with delegate type with correct instance type or with just object as instance.

Now we can discuss third overload that take only objects (in two version for void methods and with return value, exactly the same as with static methods).

public static TDelegate InstanceMethod<TDelegate>(this Type source,
    string name, params Type[] paramsTypes)
    where TDelegate : class
{
    var methodInfo = GetMethodInfo(source, name, paramsTypes);
    if (methodInfo == null)
    {
        return null;
    }
    var argsArray = Expression.Parameter(typeof(object[]));
    var sourceParameter = Expression.Parameter(typeof(object));
    var paramsExpression = new Expression[paramsTypes.Length];
    for (var i = 0; i < paramsTypes.Length; i++)
    {
        var argType = paramsTypes[i];
        paramsExpression[i] =
            Expression.Convert(Expression.ArrayIndex(argsArray, Expression.Constant(i)), argType);
    }
    Expression returnExpression = Expression.Call(Expression.Convert(sourceParameter, source),
        methodInfo, paramsExpression);
    if (methodInfo.ReturnType != typeof(void) && !methodInfo.ReturnType.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return Expression.Lambda(returnExpression, sourceParameter, argsArray).Compile() as TDelegate;
}

This method is almost the same as similar one for static methods. The only thing different is one more parameter with instance of the type, on which method should be called. Beside that it is the same: get method info, check for null, cast array of params to their types expressions, call method expression, cast return expression if needed and build lambda. For TestClass.PublicMethod it will create delegate similar to below lambda.

Func<object, object[], object> d = (o, p) => ((TestClass)o).PublicMethod((string)p[0]);

With all methods written we can test if everything work and check performance of this solution. As before with other members we can do it for all various visibilities of methods (public, internal, protected and private).

public string PublicMethodVoidParameter;

public string PublicMethod(string s)
{
    return s;
}

public void PublicMethodVoid(string s)
{
    PublicMethodVoidParameter = s;
}

internal string InternalMethod(string s)
{
    return s;
}
protected string ProtectedMethod(string s)
{
    return s;
}

private string PrivateMethod(string s)
{
    return s;
}

Test are very similar to tests for static methods.

var m1 = DelegateFactory.InstanceMethod<Func<TestClass, string, string>>("PublicMethod");
var m2 = DelegateFactory.InstanceMethod<Func<TestClass, string, string>>("InternalMethod");
var m3 = DelegateFactory.InstanceMethod<Func<TestClass, string, string>>("ProtectedMethod");
var m4 = DelegateFactory.InstanceMethod<Func<TestClass, string, string>>("PrivateMethod");
var m5 = Type.InstanceMethod<Func<TestClass, string, string>>("PublicMethod");
var m6 = Type.InstanceMethod<Func<object, string, string>>("PublicMethod");
var m7 = Type.InstanceMethod("PublicMethod", typeof(string));
var m8 = Type.InstanceMethodVoid("PublicMethodVoid", typeof(string));

var t = m1(TestInstance, "test");
var t2 = m2(TestInstance, "test");
var t3 = m3(TestInstance, "test");
var t4 = m4(TestInstance, "test");
var t5 = m5(TestInstance, "test");
var t6 = m6(TestInstance, "test");
var t7 = m7(TestInstance, new object[] { "test" });
m8(TestInstance, new object[] { "test" });
var t8 = TestInstance.PublicMethodVoidParameter;

First four above lines tests different methods with different visibility. Next two tests the same overload once with correct instance type and second time with object. Last two creates delegates with only objects for void and non-void method.

 

As you can see every created delegate works just fine. Below is similar code, that was used to test performance of delegates of static methods.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = TestInstance.PublicMethod("test");
}
_stopWatch.Stop();
Console.WriteLine("Public method directly: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = m1(TestInstance, "test");
}
_stopWatch.Stop();
Console.WriteLine("Public method proxy: {0}", _stopWatch.ElapsedMilliseconds);

var methodInfo = Type.GetMethod("PublicMethod");
_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = methodInfo.Invoke(TestInstance, new object[] { "test" });
}
_stopWatch.Stop();
Console.WriteLine("Public method proxy: {0}", _stopWatch.ElapsedMilliseconds);

Result in console output would be very much like this:

Public method directly: 1199
Public method proxy: 1287
Public method proxy: 23044

As you can see delegates for methods (exactly like with other members) are just a little slower than calling method directly. Reflection is way, way more inefficient and about 19 times slower.

 

Summary

In this article we covered how and why create delegates for constructors, static and instance methods. We are left only with events and with special type of methods: generic methods. Both static and instance methods can be generic and along with events all will be covered in next article.

Code for article can be found on github.



Faster than Reflection: Delegates. Part 1.

clock August 5, 2016 05:58 by author n.podbielski

Why not Reflection?

If you working with .NET and C# (probably other languages too) at some point you will have to write more advanced and generic code, that i.e. reads all properties of a type, searches for attributes etc. Or maybe you want to call some private method or property? It is not that rare to use some internal mechanism of framework or library. Usually first solution involves Reflection. But thing is: Reflection is slow. Of course it is sufficient if you need to use Reflection rarely and it is not main code of application. If it is used more often at some point you will probably try to optimize it. And now is the fun part: how to do it?

Main problem with Reflection is that it is slow. It is much slower then calling members of types directly. If you do this via Reflection everything slows down. If you need to create instance of a type you probably will use Activator.CreateInstance method. It is a little quicker than reflection but is also slower then calling constructor directly. For properties, methods and constructors it is possible to use expressions (Expression type static methods), but expressions and compiling them is even slower then reflection.

When I was looking for a fast way to create types instances in this article, I have found this question on Stack Overflow. According to it, fastest way to create instance is to use delegate created by compiling expression. This made me thinking about general mechanism for acquiring instances and members of types via delegates. After all it is point of interest for me lately since I work on Xamarin applications with PCL projects that have portable .NET framework with a little less features then full version. Fast mechanism for returning not available members of types would be really nice and would make PCL code bigger in the expense of platform code (which is good thing). And since you can create delegates from Reflection, Expression or lambdas and there are just a little overhead (since you have call one more method), mechanism for creating delegates for acquiring all members of a type (public and private) is a good idea. And this is main topic of this article.

 

 Following code is written in Visual Studio 2015 with use of .NET 4.5, but it is possible to port most of the code to older versions.

 

Delegates for everything

Type can have following types of members:

  1. Static
    1. Properties
    2. Methods
    3. Fields
    4. Events
    5. Constant fields
  2. Instance
    1. Properties
    2. Methods
    3. Fields
    4. Constructors
    5. Events
    6. Indexers

We can create delegates for retrieving all of this members. Frankly not all of those delegates makes sense. Delegates for constants for example. Those fields do not change, so there is no point of retrieving them more than once. You can easily retrieve those values using Reflection and save it somewhere for future use.

They only thing this article will not cover is static events. Did you ever use one? Seriously I cannot think of a case when this is absolutely needed. Much more common would to create ordinary event and invoke it from singleton instance. Good thing is that it is pretty easy to create delegate for static event with just small change for instance event.

 

 

Static Properties

Properties and methods are most common members. Methods are much more complex so it is better to start with properties.

I think most common case for reflection is retrieving set or single properties from instance or type. It may be for dynamic table views, serialization, deserialization, saving to file etc. Static properties are little less complex so we will start with them instead of instance ones.

 

Get Accessor

We should create new project. It will called Delegates - console application for easy tests.

First thing to do is to create class for tests. We can named it TestClass.

public class TestClass
{
    public static string StaticPublicProperty { get; set; } = "StaticPublicProperty";

    internal static string StaticInternalProperty { get; set; } = "StaticInternalProperty";

    protected static string StaticProtectedProperty { get; set; } = "StaticProtectedProperty";

    private static string StaticPrivateProperty { get; set; } = "StaticPrivateProperty";
}

Second thing is to create class for delegates creation - DelegatesFactory. How we can retrieve static property? Best way is to retrieve it is via Type instance that represent info about our source type. We can make it extension method for Type type. This way it will be more convenient. We need to know about property we want, so parameter with property name and type parameter with its return type is also good idea.

Type.StaticPropertyGet<string>("StaticPublicProperty");

Another way is to set source type and property type as type parameters. This way we will have static method instead of an extension method. Also it would be less usable since we often do not have type name in compile time (because it is not public or not available before runtime).

DelegateFactory.StaticPropertyGet<TestClass, string>("StaticPublicProperty");

With this assumption we can write console application as test for DelegateFactory.

class ConsoleApplication
{
    private static readonly Type Type = typeof(TestClass);

    static void Main(string[] args)
    {
        var sp = DelegateFactory.StaticPropertyGet<TestClass, string>("StaticPublicProperty");
        var sp1 = Type.StaticPropertyGet<string>("StaticPublicProperty");
    }
}

Now we can write stub of both methods.

public static class DelegateFactory
{
    public static Func<TProperty> StaticPropertyGet<TSource, TProperty>(string propertyName)
    {
        return null;
    }

    public static Func<TProperty> StaticPropertyGet<TProperty>(this Type source, string propertyName)
    {
        return null;
    }
}

Since second method (extension one) is more general we will implement it first. To create delegate we need PropertyInfo for requested property. Yes, we need reflection for that. Thing is, that much of delegates requires reflection, but it is just one time, for creation of delegate. After that we can use this delegate with just small overhead, since program have to execute two nested methods instead of one.

Most important part in retrieving property via reflection is that we have access to PropertyInfo.GetMethod that way and GetMethod is MethodInfo type which have CreateDelegate member. Simplest code for creating delegate for retrieving static public property looks like this.

public static Func<TProperty> StaticPropertyGet<TProperty>(this Type source, string propertyName)
{
    var propertyInfo = source.GetProperty(propertyName, BindingFlags.Static);
    return (Func<TProperty>)propertyInfo.GetMethod.CreateDelegate(typeof(Func<TProperty>));
}

Looks really simple, which is why this is first example. CreateDelegate method requires type of delegate to create. For property retrieving it is Func with just one parameter, which is type of property, so created delegate will not have any parameters. Just simple parameterless method that returns value of static property.

Next thing is to handle non-public (internal, protected and private) properties. We can do it by changing set BindingFlags in GetProperty method. For private and protected members we just need one more BindingFlags.NonPublic. For internals this is little more complicated (and in my opinion more confusing) and requires both flags Public and NonPublic. Easy way to understand that is to think of internals as kind-of public, but not completely Smile.

public static Func<TProperty> StaticPropertyGet<TProperty>(this Type source, string propertyName)
{
    var propertyInfo = source.GetProperty(propertyName, BindingFlags.Static);
    if (propertyInfo == null)
    {
        propertyInfo = source.GetProperty(propertyName, BindingFlags.Static | BindingFlags.NonPublic);
    }
    if (propertyInfo == null)
    {
        propertyInfo = source.GetProperty(propertyName,
            BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
    }
    return (Func<TProperty>)propertyInfo.GetMethod.CreateDelegate(typeof(Func<TProperty>));
}

 Above code is pretty easy to understand. If property is not public it tries to find if as private or protected. If this also not the case it tries internal. Now we can write method body for overload with type parameters.

public static Func<TProperty> StaticPropertyGet<TSource, TProperty>(string propertyName)
{
    return typeof(TSource).StaticPropertyGet<TProperty>(propertyName);
}

Now we can test both methods. We should create delegates for all static properties of TestClass in console application and use them to retrieve properties values, to test if everything works.

class ConsoleApplication
{
    private static readonly Type Type = typeof(TestClass);

    static void Main(string[] args)
    {
        var sp = DelegateFactory.StaticPropertyGet<TestClass, string>("StaticPublicProperty");
        var sp1 = Type.StaticPropertyGet("StaticPublicProperty");
        var sp2 = Type.StaticPropertyGet("StaticInternalProperty");
        var sp3 = Type.StaticPropertyGet("StaticProtectedProperty");
        var sp4 = Type.StaticPropertyGet("StaticPrivateProperty");

        Console.WriteLine("Static public property value: {0}",sp1());
        Console.WriteLine("Static internal property value: {0}", sp2());
        Console.WriteLine("Static protected property value: {0}", sp3());
        Console.WriteLine("Static private property value: {0}", sp4());
    }
}

After running this example we will see result in console.

Static public property value: StaticPublicProperty
Static internal property value: StaticInternalProperty
Static protected property value: StaticProtectedProperty
Static private property value: StaticPrivateProperty

Static properties works just fine Smile.

We can check performance of those delegates a little. First we need to add two new fields to console application type.

private static Stopwatch _stopWatch;
private static double _delay = 1e8;

Second is to write loops for tests.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = TestClass.StaticPublicProperty;
}
_stopWatch.Stop();
Console.WriteLine("Static Public property: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = sp1();
}
_stopWatch.Stop();
Console.WriteLine("Static Public property retriever: {0}", _stopWatch.ElapsedMilliseconds);

First for loop retrieves static property in ordinary way. Second one uses delegates. After running changed code we can find out that difference is not that big, really.

Static Public property: 404
Static Public property retriever: 472

Retriving property value one hundred million times takes around 400ms and using delegate for that is less than 20% slower. Doing more tests you can check that real performance overhead varies between 15-35%. Of course it is just simple string. With more complex properties that are calculating its return value first, difference would be smaller. Just for a sake of an experiment we can add one more loop with reflection.

_stopWatch = new Stopwatch();
var pi0 = Type.GetProperty("StaticPublicProperty", BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public).GetMethod;
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = pi0.Invoke(null, null);
}
_stopWatch.Stop();
Console.WriteLine("Static Public property via reflection: {0}", _stopWatch.ElapsedMilliseconds);

After running changed code test results should be similar to this:

Static Public property: 423
Static Public property retriever: 535
Static Public property via reflection: 13261

As you can see reflection is many times slower. Access to static property is less than half of a second, and doing the same via reflection takes around 13 seconds!

Even by using reflection only one time to create delegate is much more efficient than using it all the time to access that property.

To have complete look on things, let us do one more test. If you ever used Expression type and its method you know that it can be used for similar things as reflection. Certainly it is possible to create delegate for static property this way.

public static Func<TProperty> StaticPropertyGet2<TProperty>(this Type source, string propertyName)
{
    var te = Expression.Lambda(Expression.Property(null, source, propertyName));
    return (Func<TProperty>)te.Compile();
}

This code is much simpler than one with reflection. It creates lambda function that could look like this for TestClass.StaticPublicProperty.

() => TestClass.StaticPublicProperty

Now we can test performance of creation of delegates by using reflection and expression.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < 10000; i++)
{
    Type.StaticPropertyGet<string>("StaticPublicProperty");
}
_stopWatch.Stop();
Console.WriteLine("Static public field creator via reflection: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < 10000; i++)
{
    Type.StaticPropertyGet2<string>("StaticPublicProperty");
}
_stopWatch.Stop();
Console.WriteLine("Static public field creator via expression: {0}", _stopWatch.ElapsedMilliseconds);

After running this example we will get results for both loops.

Static public field creator via reflection: 23
Static public field creator via expression: 543

As we can see expression is much, much more slower than reflection. I do not investigate this further, but I think that it have something to do with compiling expression to delegate. Unfortunately it is not possible to creates delegates for all members just by using reflection so it is necessity to use expressions for some of them, but we will try to not to if this is possible.

There is still the case when we do not know type of property. What to do then? Since both of StaticPropertyGet require an actual property type we cannot use them. In that case we need an overload without this type, but what to use instead? What type should delegate return? There is only one option: object. All types in .NET can be casted to object.

Func<object> spg = Type.StaticPropertyGet("StaticPublicProperty");

Returned delegate supposed to be a method that do not takes parameters and returns value of type object. How to implement this new StaticPropertyGet? We need code for retrieving PropertyInfo for needed static property. Best thing is to create new method in DelegateFactory using code from StaticPropertyGet<TProperty> extension method.

private static PropertyInfo GetStaticPropertyInfo(Type source, string propertyName)
{
    var propertyInfo = (source.GetProperty(propertyName, BindingFlags.Static) ??
                               source.GetProperty(propertyName, BindingFlags.Static | BindingFlags.NonPublic)) ??
                               source.GetProperty(propertyName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
    return propertyInfo;
}

Main problem is that sometimes we want to retrieve or set property of a value that is of unknown type at compile time. For that we need method that creates delegates that retrieves object type value instead of property type value. We can do it by using expressions since we cannot use just CreateDelegate method (it requires compatible delegate signature). Core of this mechanism is Expression.Lambda method, that returns LambdaExpression type object, and LambdaExpression.Compile method that returns Delegate type. With those two we can create pretty much any code that involves accessing of types members.

public static Func<object> StaticPropertyGet(this Type source, string propertyName)
{
    var propertyInfo = GetStaticPropertyInfo(source, propertyName);
    return (Func<object>)Expression.Lambda(Expression.Call(propertyInfo.GetMethod)).Compile();
}

Expression.Lambda creates lambda with correct method signature. Expression.Call is used to mark in body of a lambda that call to a property getter should be made - after all property getter is really get_{property name} method.

We can test if this works correctly with following code.

var spg = Type.StaticPropertyGet("StaticPublicProperty");
Console.WriteLine(spg());

Above lines executed will write value of 'StaticPublicProperty', which is value of property with this name.

 

Set accessors

Now when we have a way to get values of static properties, we can write methods for retrieving delegates for set accessors. Mechanism is very similar to get accessors, but instead of Func<TProperty> Action<TProperty> is used. Of course PropertyInfo.SetMethod creates delegate instead of GetMethod.

public static Action<TProperty> StaticPropertySet<TSource, TProperty>(string propertyName)
{
    return typeof(TSource).StaticPropertySet<TProperty>(propertyName);
}
public static Action StaticPropertySet(this Type source, string propertyName)
{
    var propertyInfo = GetStaticPropertyInfo(source, propertyName);
    return (Action)propertyInfo.SetMethod.CreateDelegate(typeof(Action));
}

As before, for get accessors, there are two methods that uses only reflection: one extension method and one with type parameter as source type.

For overload that do not require property type to be known in advance we have to use expressions as before with StaticPropertyGet.

public static Action<object> StaticPropertySet(this Type source, string propertyName)
{
    var propertyInfo = GetStaticPropertyInfo(source, propertyName);
    var valueParam = Expression.Parameter(typeof(object));
    var convertedValue = Expression.Convert(valueParam, propertyInfo.PropertyType);
    return (Action<object>)Expression.Lambda(Expression.Call(propertyInfo.SetMethod, convertedValue), valueParam).Compile();
}

This expression is a bit more complicated. Since it should return method that returns void and have one parameter, we need to add this parameter to Lambda call - hence valueParam variable. If you are wondering why it cannot be embedded into Expression.Lambda, the same parameter expression has to be passed to Convert and Lambda methods - expression are compared by reference. Variable valueParam has to be converted to correct type before passing to property setter method. If not expression would be valid and would failed to create. After conversion, new expression can be safely passed as parameter to Call method. Not converted expression in valueParam variable is passed as parameter to Lambda call, to mark, that created lambda will have single parameter with type of object.

New methods are called exactly the same way.

var sps = DelegateFactory.StaticPropertySet<TestClass, string>("StaticPublicProperty");
var sps1 = Type.StaticPropertySet<string>("StaticPublicProperty");
var sps2 = Type.StaticPropertySet<string>("StaticInternalProperty");
var sps3 = Type.StaticPropertySet<string>("StaticProtectedProperty");
var sps4 = Type.StaticPropertySet<string>("StaticPrivateProperty");
var spg5 = Type.StaticPropertyGet("StaticPublicProperty");

In console application we can create test loops like below.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    TestInstance.PublicProperty = "ordinal way";
}
_stopWatch.Stop();
Console.WriteLine("Public set property: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    sps1("test");
}
_stopWatch.Stop();
Console.WriteLine("Public set property retriever: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    sps2("test");
}
_stopWatch.Stop();
Console.WriteLine("Internal set property retriever: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    sps3("test");
}
_stopWatch.Stop();
Console.WriteLine("Protected set property retriever: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    sps4("test");
}
_stopWatch.Stop();
Console.WriteLine("Private set property retriever: {0}", _stopWatch.ElapsedMilliseconds);

Console.WriteLine("Static public property value is {0}", sp1());
Console.WriteLine("Static internal property value is {0}", sp2());
Console.WriteLine("Static protected property value is {0}", sp3());
Console.WriteLine("Static private property value is {0}", sp4());

After running above code we will see result with values similar to the ones below.

Public set property: 483
Public set property retriever: 542
Internal set property retriever: 496
Protected set property retriever: 497
Private set property retriever: 542
Static public property value is test
Static internal property value is test
Static protected property value is test
Static private property value is test

As you can see accessing setters this way is just a little slower, similarly to accessing getters by delegates.

 

Improvements

What can be done better? Certainly code above is not very safe since there are at least two points when it can throw null reference exception. First, when property was not found and propertyInfo variable is null and second when get or set accessor is not available (not every property have both, right?). Both cases are easy to fix.

We should write properties to test those cases first.

public static string StaticOnlyGetProperty => _staticOnlyGetOrSetPropertyValue;

public static string StaticOnlySetProperty
{
    set { _staticOnlyGetOrSetPropertyValue = value; }
}
private static string _staticOnlyGetOrSetPropertyValue = "StaticOnlyGetOrSetPropertyValue";

Now we can fix both methods.

public static Func<TProperty> StaticPropertyGet<TProperty>(this Type source, string propertyName)
{
    var propertyInfo = GetStaticPropertyInfo(source, propertyName);
    return (Func<TProperty>)propertyInfo?.GetMethod?.CreateDelegate(typeof(Func<TProperty>));
}

public static Action<TProperty> StaticPropertySet<TProperty>(this Type source, string propertyName)
{
    var propertyInfo = GetStaticPropertyInfo(source, propertyName);
    return (Action<TProperty>)propertyInfo?.SetMethod?.CreateDelegate(typeof(Action<TProperty>));
}

As you can see, simple null check in both methods is enough, but we should test it anyway. Following calls in console application will suffice.

 

All calls returns null, which is good. We wanted null instead of error.

 

Properties

With static properties covered we can now switch focus to instance properties. Delegates for those are different only by one parameter. Since instance properties need instance to get values of those properties from, delegates will need parameters with those instance. So instead of Func<TProperty> will use Func<TSource,TProperty> delegates. Rest of the code is almost the same. As for static properties we have three methods for each accessor. First, static method with source type parameter and property type parameter, extension method with type parameter the same as property type and method without type parameters. But firs we need method similar to GetStaticPropertyInfo.

private static PropertyInfo GetPropertyInfo(Type source, string propertyName)
{
    var propertyInfo = source.GetProperty(propertyName) ??
                               source.GetProperty(propertyName, BindingFlags.NonPublic) ??
                               source.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    return propertyInfo;
}

As you can see it is very similar too

We will start with first type of method for each accessor.

public static Func<TSource, TProperty> PropertyGet<TSource, TProperty>(string propertyName)
{
    var source = typeof(TSource);
    var propertyInfo = GetPropertyInfo(source, propertyName);
    return (Func<TSource, TProperty>)propertyInfo?.GetMethod?.CreateDelegate(typeof(Func<TSource, TProperty>));
}

public static Action<TSource, TProperty> PropertySet<TSource, TProperty>(string propertyName)
{
    var source = typeof(TSource);
    var propertyInfo = GetPropertyInfo(source, propertyName);
    return (Action<TSource, TProperty>)propertyInfo?.SetMethod?.CreateDelegate(typeof(Action<TSource, TProperty>));
}

As you can see there is null propagation operator (?.) used for null check of property info and needed accessor method.

Ok. To test it we need to create instance properties in TestClass in console application.

public class TestClass
{
    public TestClass()
    {
        PublicProperty = "PublicProperty";
        InternalProperty = "InternalProperty";
        ProtectedProperty = "ProtectedProperty";
        PrivateProperty = "PrivateProperty";
    }

    public string PublicProperty { get; set; }

    internal string InternalProperty { get; set; }

    protected string ProtectedProperty { get; set; }

    private string PrivateProperty { get; set; }

}

 And static readonly instance of TestClass type in console application to use in all test that involves instance.

private static readonly TestClass TestInstance = new TestClass();

Test code looks like below.

var ps1 = DelegateFactory.PropertySet<TestClass, string>("PublicProperty");
var ps2 = DelegateFactory.PropertySet<TestClass, string>("InternalProperty");
var ps3 = DelegateFactory.PropertySet<TestClass, string>("ProtectedProperty");
var ps4 = DelegateFactory.PropertySet<TestClass, string>("PrivateProperty");
            
Console.WriteLine("Public property value is {0}", pg1(TestInstance));
Console.WriteLine("Internal property value is {0}", pg2(TestInstance));
Console.WriteLine("Protected property value is {0}", pg3(TestInstance));
Console.WriteLine("Private property value is {0}", pg4(TestInstance));

ps1(TestInstance, "test");
ps2(TestInstance, "test");
ps3(TestInstance, "test");
ps4(TestInstance, "test");

Console.WriteLine("Public property value is {0}", pg1(TestInstance));
Console.WriteLine("Internal property value is {0}", pg2(TestInstance));
Console.WriteLine("Protected property value is {0}", pg3(TestInstance));
Console.WriteLine("Private property value is {0}", pg4(TestInstance));

After running this test code we will see console output like this.

Public property value is PublicProperty
Internal property value is InternalProperty
Protected property value is ProtectedProperty
Private property value is PrivateProperty
Public property value is test
Internal property value is test
Protected property value is test
Private property value is test

First four lines are values returned by get delegates and are consistent with default values of TestClass instance. Four next lines are after calls to set delegates and have new 'test' values. Good. Everything works!

Improvements

Main problem with methods like above for retrieving and setting instance properties is that those require type know at compile time, which is sometimes impossible since some types are private. But if you do not have type you cannot create delegate that have this type instance as parameter. The only solution for this is to create method that takes object and hopes that it is correct instance of correct type Smile Problem with that solution is that you cannot pass parameter of type of object to property getter as source instance. You first have to cast it to appropriate type. So instead of just one proxy method you have cast to appropriate type too inside this proxy method, that retrieves or sets property. This is the point when we have to use expressions as in static properties.

Second problem is the same as with static properties. You do not necessarily have to know property type at compilation time. It may be either unavailable or private.

First of all our new overloads would look like this:

Type.PropertyGet<string>("PublicProperty");
Type.PropertyGet("PublicProperty");

Pretty simple. In first case we know type of property and in second one - we do not. First would return string and second one the same string but as object type.

We need two new overloads for PropertyGet method then. Let us start with the one with known property type since it will be only a bit, but a little simpler nevertheless.

With property info returned from GetPropertyInfo method, we can create appropriate delegate with Expression class. Code for accessing property getter by its instance as object looks like this.

var sourceObjectParam = Expression.Parameter(typeof(object));
var @delegate = (Func<object, object>)Expression.Lambda(Expression.Call(Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod), sourceObjectParam).Compile();

Mechanism is simple. First we need to create ParameterExpression with object type. It is necessary because it is referenced twice: in Expression.Lambda method as target lambda parameter and in Expression.Convert method as a target of a conversion. After that we create lambda expression (Expression.Lambda method) with body with method call (Expression.Call method) to property getter with parameter of the call from result of conversion (Expression.Convert method) of lambda object parameter. It may looks complicated (even more since Expression API is in my opinion a little chaotic; notice that Lambda method takes first body of a method, then parameters, but Call method first takes subject of a call and then method to call), but in reality it is not. After compilation expression will be roughly equivalent to lambda like below.

Func<object,string> @delegate = o => ((TestClass)o).PublicProperty;

Looks much clearer, right? Smile

With this knowledge we can create first method.

public static Func<object, TProperty> PropertyGet<TProperty>(this Type source, string propertyName)
{
    var propertyInfo = GetPropertyInfo(source, propertyName);
    var sourceObjectParam = Expression.Parameter(typeof(object));
    return (Func<object, TProperty>)Expression.Lambda(Expression.Call(Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod), sourceObjectParam).Compile();
}

The same way we can create second method, but with different declaration of return type. It is very important to mark, that even if method with return type object, written in C# can work without cast to object in return statement (because any type can be implicitly casted to object without extra casting), this do not work in expressions. As far as I can tell from my tests it works only for reference type. For value types such as int, DateTime etc. we need conversion to object. PropertyInfo class have IsClass property that allows to check if conversion is needed or not.

public static Func<object, object> PropertyGet(this Type source, string propertyName)
{
    var propertyInfo = GetPropertyInfo(source, propertyName);
    var sourceObjectParam = Expression.Parameter(typeof(object));
    Expression returnExpression = 
        Expression.Call(Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod);
    if (!propertyInfo.PropertyType.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return (Func<object, object>)Expression.Lambda(returnExpression, sourceObjectParam).Compile();
}

As you can see second method is more generic and almost the same as first. Because of that we can safely rewrite first method like below.

public static Func<object, TProperty> PropertyGet<TProperty>(this Type source, string propertyName)
{
    return source.PropertyGet(propertyName) as Func<object, TProperty>;
}

After adding new property to TestClass, with int type, PublicPropertyInt and following lines to console application we can test if those methods works.

var pgo1 = Type.PropertyGet<string>("PublicProperty");
var pgo2 = Type.PropertyGet("PublicProperty");
var pgo3 = Type.PropertyGet("PublicPropertyInt");
Console.WriteLine("Public property by object and property type {0}", pgo1(TestInstance));
Console.WriteLine("Public property by objects {0}", pgo2(TestInstance));
Console.WriteLine("Public property by objects and with return value type {0}", pgo3(TestInstance));

It will result in following lines in console output.

Public property by object and property type PublicProperty
Public property by objects PublicProperty
Public property by objects and with return value type 0

Now we can write similar methods for setters. Core difference is that correct delegate will be Action instead of Func so instead of one parameter it will have to: instance and value to set. In method with known parameter type we only have change delegate but in the one without type parameters we have to convert instance and value. We will start with second one. First we have to create ExpressionParameter for new property value.

var propertyValueParam = Expression.Parameter(propertyInfo.PropertyType);

With this we can change returning value of lambda (if we changing similar PropertyGet method).

return (Action<object, object>)Expression.Lambda(Expression.Call(
Expression.Convert(sourceObjectParam, source),
propertyInfo.SetMethod,
Expression.Convert(propertyValueParam, propertyInfo.PropertyType)), sourceObjectParam, propertyValueParam).Compile();

As you can see its creates Action delegate with two parameters - sourceObjectParam and propertyValueParam - both are converted to correct type first. Above lines could be converted to following lambda.

Action<object, object> @delegate = (i, v)=>((TestClass)i).PublicProperty = (string)v;

PropertySet overload with known property type is more specific then above method, but in the same time it have knowledge of both types: value parameter and property type. This is why we can use its code for both overloads. Just if property type is correct there is no need for conversion.

Final version of both looks like this.

public static Action<object, TProperty> PropertySet<TProperty>(this Type source, string propertyName)
{
    var propertyInfo = GetPropertyInfo(source, propertyName);
    var sourceObjectParam = Expression.Parameter(typeof(object));
    ParameterExpression propertyValueParam;
    Expression valueExpression;
    if (propertyInfo.PropertyType == typeof(TProperty))
    {
        propertyValueParam = Expression.Parameter(propertyInfo.PropertyType);
        valueExpression = propertyValueParam;
    }
    else
    {
        propertyValueParam = Expression.Parameter(typeof(TProperty));
        valueExpression = Expression.Convert(propertyValueParam, propertyInfo.PropertyType);
    }
    return (Action<object, TProperty>)Expression.Lambda(Expression.Call(Expression.Convert(sourceObjectParam, source), propertyInfo.SetMethod, valueExpression), sourceObjectParam, propertyValueParam).Compile();
}

public static Action<object, object> PropertySet(this Type source, string propertyName)
{
    return source.PropertySet<object>(propertyName);
}

 Last thing that should be fix is null checking for GetMethod and SetMethod - after all it is already done in previous examples. This require single if in PropertySet and PropertyGet methods.

var propertyInfo = GetPropertyInfo(source, propertyName);
if (propertyInfo?.GetMethod == null)
{
    return null;
}

var propertyInfo = GetPropertyInfo(source, propertyName);
if (propertyInfo?.SetMethod == null)
{
    return null;
}

If either property of accessor do not exists (after all properties do not always have both set and get accessor) method will return null instead of delegate.

 

Indexers

Indexers are just special type of instance properties. Best way to thing about them is as special kind of get and set accessors, with extra index parameters. And they actually are special properties with name "Item". We should start with creating indexer in our test class.

private readonly List<int> _indexerBackend = new List<int>(10);

public int this[int i]
{
    get
    {
        return _indexerBackend[i];
    }
    set { _indexerBackend[i] = value; }
}

Yes there is no index checking, nor automatic collection resizing, etc. It is just test code so it do not need to be safe.

This is really easy case and delegate for this will be also everything but complex. We need Func<TestInstance,int,int> for this indexer. Simplest way to create it with single call will be like below.

var ig1 = DelegateFactory.IndexerGet<TestClass, int, int>();

How to implement IndexerGet method? Most important is to get PropertyInfo object for indexer.

private const string Item = "Item";

private static PropertyInfo GetIndexerPropertyInfo(Type source, Type returnType, Type[] indexesTypes) { var propertyInfo = (source.GetProperty(Item, returnType, indexesTypes) ?? source.GetProperty(Item, BindingFlags.NonPublic, null, returnType, indexesTypes, null)) ?? source.GetProperty(Item, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, returnType, indexesTypes, null); return propertyInfo; }

For public indexer way to obtain PropertyInfo is almost the same as for property - of course there is need for two new parameters that indicate return and indexes type of desired indexer. For non-public indexer things get a little more complicated since we have to use more general overload. Of course all of calls to GetProperty method use constant value "Item" as name of property. With property info we can create delegate for indexer with single index parameter very similar to delegate for ordinary property.

public static Func<TSource, TIndex, TReturn> IndexerGet<TSource, TReturn, TIndex>()
{
    var propertyInfo = GetIndexerPropertyInfo(typeof(TSource), typeof(TReturn), new[] { typeof(TIndex) });
    return (Func<TSource, TIndex, TReturn>)
            propertyInfo?.GetMethod?.CreateDelegate(typeof(Func<TSource, TIndex, TReturn>));
}

As you can see the main difference is that instead just one parameter with instance (like in properties) there are one more extra with index parameter. Beside that it is pretty much the same.

Ok, but what if indexer have more than one index? How about two or three? It is possible too and since IndexerGet method takes type parameters we cannot make more universal method that returns different delegate for 2, 3, 4 or more parameters. For each of those types of indexers there is necessity for another methods with different set of types parameters. Since indexers are rarely used and mostly for indexing operations of some kind, we will create methods for only up to 3 index parameters (for up to 3D arrays).

public static Func<TSource, TIndex, TIndex2, TReturn> IndexerGet<TSource, TReturn, TIndex, TIndex2>()
{
    var propertyInfo = GetIndexerPropertyInfo(typeof(TSource), typeof(TReturn), new[] { typeof(TIndex), typeof(TIndex2) });
    return (Func<TSource, TIndex, TIndex2, TReturn>)
            propertyInfo?.GetMethod?.CreateDelegate(typeof(Func<TSource, TIndex, TIndex2, TReturn>));
}

public static Func<TSource, TIndex, TIndex2, TIndex2, TReturn> IndexerGet<TSource, TReturn, TIndex, TIndex2, TIndex3>()
{
    var propertyInfo = GetIndexerPropertyInfo(typeof(TSource), typeof(TReturn), new[] { typeof(TIndex), typeof(TIndex2), typeof(TIndex3) });
    return (Func<TSource, TIndex, TIndex2, TIndex2, TReturn>)
            propertyInfo?.GetMethod?.CreateDelegate(typeof(Func<TSource, TIndex, TIndex2, TIndex2, TReturn>));
}

Above method will spawn delegates for two and three indexes and are called very similar to 1D array indexer overload. There is of course possibility of writing methods that returns delegates for more indexes, up to 16 - it is limit of Func class.

var ig1 = DelegateFactory.IndexerGet<TestClass, int, int, int>();
var ig2 = DelegateFactory.IndexerGet<TestClass, int, int, int, int>();

As you probably already noticed all of above methods for indexers getters can only create delegates only if we know type of class. If we do not (because it is private or not know it in compile-time) we need a method that takes Type parameter instead. We can use the same extension method convention as before with properties.

var ig1 = Type.IndexerGet<int, int>();
var ig2 = Type.IndexerGet<int, int, int>();
var ig3 = Type.IndexerGet<int, int, int, int>();

The same problem occurs with indexers as with properties before. Since we do pass instance and not the type itself we can't create delegates with known type of parameter - it needs to be object. Because of that we again need expressions. We will start with indexer with single index parameter.

public static Func<object, TIndex, TReturn> IndexerGet<TReturn, TIndex>(this Type source)
{
    var indexType = typeof(TIndex);
    var returnType = typeof(TReturn);
    var propertyInfo = GetIndexerPropertyInfo(source, returnType, new[] { indexType });
    var sourceObjectParam = Expression.Parameter(typeof(object));
    var paramExpression = Expression.Parameter(indexType);
    return (Func<object, TIndex, TReturn>)Expression.Lambda(
        Expression.Call(Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod, paramExpression), sourceObjectParam, paramExpression).Compile();
}

It is very similar to PropertyGet method that creates delegate that takes object as source instance. Difference is again with index parameter. Because it is an object there is need for conversion first. After creating lambda expression that takes instance object and index parameters, it is then compiled and returned as delegate. It can be represented as following lambda statement.

Func<object, int, int> @delegate = (o, i) => ((TestClass)o)[i];

Ok. How about two or three indexes? Luckily Expression.Lambda and Expression.Call methods, have overloads that takes unspecified number of parameters. With that we can easily rewrite most of the code for creating delegate, to more universal version. We should write method that creates Delegate instance by compiling expression from indexer return type and indexes types.

public static Delegate DelegateIndexerGet(Type source, Type returnType, params Type[] indexTypes)
{
    var propertyInfo = GetIndexerPropertyInfo(source, returnType, indexTypes);
    var sourceObjectParam = Expression.Parameter(typeof(object));
    var paramsExpression = new ParameterExpression[indexTypes.Length];
    for (var i = 0; i < indexTypes.Length; i++)
    {
        var indexType = indexTypes[i];
        paramsExpression[i] = Expression.Parameter(indexType);
    }
    return Expression.Lambda(
                Expression.Call(Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod, paramsExpression),
                new[] { sourceObjectParam }.Concat(paramsExpression)).Compile();
}

Most important change is that this method takes unspecified number of indexes types. Second change is that instead of known number of parameters in Lambda and Call we have collection of parameters (with one more in lambda - source instance parameter). Aside of that it is the same code as before and with this new method we can implement tree extension methods above.

public static Func<object, TIndex, TReturn> IndexerGet<TReturn, TIndex>(this Type source)
{
    var indexType = typeof(TIndex);
    return (Func<object, TIndex, TReturn>)DelegateIndexerGet(source, typeof(TReturn), indexType);
}
        
public static Func<object, TIndex, TIndex2, TReturn> IndexerGet<TReturn, TIndex, TIndex2>(this Type source)
{
    var indexType = typeof(TIndex);
    var indexType2 = typeof(TIndex2);
    return (Func<object, TIndex, TIndex2, TReturn>)DelegateIndexerGet(source, typeof(TReturn), indexType, indexType2);
}

public static Func<object, TIndex, TIndex2, TIndex3, TReturn> IndexerGet<TReturn, TIndex, TIndex2, TIndex3>(this Type source)
{
    var indexType = typeof(TIndex);
    var indexType2 = typeof(TIndex2);
    var indexType3 = typeof(TIndex3);
    return (Func<object, TIndex, TIndex2, TIndex3, TReturn>)DelegateIndexerGet(source, typeof(TReturn), indexType, indexType2, indexType3);
}

It is straightforward code. Type parameters are changed to instances of Type class and passed to DelegateIndexerGet method. Returned value is casted to expected Func class. But those new method still lacks some features though. Indexers are not required to have primitive index types - they can be anything. Even if this is rarely the case we have to have way to create delegates for more indexing parameters. But much more important is return type of indexer - it can any type and it is more common. We need more generic method then. For starters we can create method that creates delegate Func<object,object,object> for indexers that have only one parameter.

public static Func<object, object, object> IndexerGet(this Type source, Type returnType, Type indexType)
{
    var propertyInfo = GetIndexerPropertyInfo(source, returnType, new[] { indexType });
    var sourceObjectParam = Expression.Parameter(typeof(object));
    var indexObjectParam = Expression.Parameter(typeof(object));
    Expression returnExpression = Expression.Call(Expression.Convert(sourceObjectParam, source),
        propertyInfo.GetMethod, Expression.Convert(indexObjectParam, indexType));
    if (!propertyInfo.PropertyType.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return (Func<object, object, object>)
        Expression.Lambda(returnExpression, sourceObjectParam, indexObjectParam).Compile();
}

It is almost the same as PropertyGet overload that works on objects instead of concrete types - it just takes one parameter more.

Ideally would be to have a way to get all of indexer types in uniform way. It is possible, for example, to write delegate that takes two parameters: instance and array of indexes and returns object.

var ig = Type.IndexerGet(typeof(int), typeof(int), typeof(int), typeof(int));
var t = ig(TestInstance, new object[] { 0, 0, 0 });

Problem with this method is that it requires much more calculation which involves reading array of indexes, converting them to correct types, calling indexer getter and converting its value to object. Because all of that it will be much slower than just call to getter, but if we do not have luxury of more strict delegate (like Func<TSource, TIndex, TReturn>) it is best we can do.

public static Func<object, object[], object> IndexerGet(this Type source, Type returnType, params Type[] indexTypes)
{
    var propertyInfo = GetIndexerPropertyInfo(source, returnType, indexTypes);
    var sourceObjectParam = Expression.Parameter(typeof(object));
    var indexesParam = Expression.Parameter(typeof(object[]));
    var paramsExpression = new Expression[indexTypes.Length];
    for (var i = 0; i < indexTypes.Length; i++)
    {
        var indexType = indexTypes[i];
        paramsExpression[i] = Expression.Convert(Expression.ArrayIndex(indexesParam, Expression.Constant(i)), indexType);
    }
    Expression returnExpression =
        Expression.Call(Expression.Convert(sourceObjectParam, source), propertyInfo.GetMethod, paramsExpression);
    if (!propertyInfo.PropertyType.IsClass)
    {
        returnExpression = Expression.Convert(returnExpression, typeof(object));
    }
    return (Func<object, object[], object>)Expression.Lambda(
        returnExpression, sourceObjectParam, indexesParam).Compile();
}

Main change from previous methods is that we have single parameter with all indexes passed to lambda in ParameterExpression.

var indexesParam = Expression.Parameter(typeof(object[]));

Since this is an array of indexes we need to get every single one of them from it. It can be done by Expression.ArrayIndex method. After retrieving index value we need to cast it to index type at the same position. With collection of converted indexes we can pass it to Expression.Call as collection of indexer getter parameters. There is similar change (if we comparing code with PropertyGet method without type parameters), that returns object instead of property type instance: if return type is value type (int, byte etc.) conversion to object is done. Here is translation to more common lambda statement.

Func<object, object[], object> @delegate = (o, i) => (object)((TestClass)o)[(int)i[0], (int)i[1], (int)i[3]];

Yes, of course there is no checking if indexes or instance is of correct type. There is no checking if array of indexes have correct size nor check for index types. There plenty of things that may go wrong. But we do write delegates for speed not for safety. And if we are talking about performance it is about time to test it. We should add few indexers to TestClass first.

public int this[int i1, int i2, int i3]
{
    get { return i1; }
    set
    {
    }
}

internal string this[string s] => s;

private long this[long s] => s;

private int this[int i1, int i2]
{
    get { return i1; }
    set { }
}

Test code for above indexers and first one looks like this.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = TestInstance[0];
}
_stopWatch.Stop();
Console.WriteLine("Public indexer: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = ig1(TestInstance, 0);
}
_stopWatch.Stop();
Console.WriteLine("Public indexer retriever: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = TestInstance[0, 0, 0];
}
_stopWatch.Stop();
Console.WriteLine("Multiple index indexer directly: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = ig10(TestInstance, new object[] { 0, 0, 0 });
}
_stopWatch.Stop();
Console.WriteLine("Multiple index indexer via delegate with array: {0}", _stopWatch.ElapsedMilliseconds);

var indexerInfo = Type.GetProperty("Item", typeof(int), new Type[] { typeof(int), typeof(int), typeof(int) });
_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = indexerInfo.GetValue(TestInstance, new object[] { 0, 0, 0 });
}
_stopWatch.Stop();
Console.WriteLine("Multiple index indexer via reflection: {0}", _stopWatch.ElapsedMilliseconds);

Running this code will results in console output as below.

Public indexer: 1555
Public indexer retriever: 1603
Multiple index indexer directly: 525 Multiple index indexer via delegate with array: 5847 Multiple index indexer via reflection: 44755

As you can see calling indexer by proxy delegate is not that much slower. Of course for more complex indexers then calling indexing operation on backend field like in first indexer in TestClass will make this difference even less visible. Another thing worth mentioning is that calling delegate with array instead of set of parameters make it much slower than original indexer. In test indexer it is about ten times slower. Difference is that big because indexer itself is just single return operation when delegate have to index and convert all of parameters and pass it to indexer. Difference would probably be even greater for indexers with more than three parameters (another thing is why write such indexer then instead of single method). From another hand, if indexer would be more complex difference would be less visible. Anyway still delegate is few times quicker than reflection call.

 

Improvements

In some cases there might be small problem. Indexer name not necessarily have to be an 'Item'. According to documentation it can be changed like this.

[System.Runtime.CompilerServices.IndexerName("TheItem")]
internal string this[string s] => s;

Do anybody ever used that? Smile I do not think that it is very common, but it do not matter. We can make it work anyway. We could write new overloads of our methods with indexer name parameter, but it would require too much work and since we are smart and lazy there is a better way Wink. There is possibility of renaming indexer property, but you have to do it for all indexers at once in the same class. GetIndexerPropertyInfo method already looks for indexer info few times. Why do not force it to do that few more times? If 'Item' is not there, we can search for other properties that are indexers.

private static PropertyInfo GetIndexerPropertyInfo(Type source, Type returnType, Type[] indexesTypes,
    string indexerName = null)
{
    indexerName = indexerName ?? Item;

    var propertyInfo = (source.GetProperty(indexerName, returnType, indexesTypes) ??
                        source.GetProperty(indexerName, BindingFlags.NonPublic, null,
                            returnType, indexesTypes, null)) ??
                        source.GetProperty(indexerName,
                            BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
                            null, returnType, indexesTypes, null);
    if (propertyInfo != null)
    {
        return propertyInfo;
    }
    var indexer = source.GetProperties().FirstOrDefault(p => p.GetIndexParameters().Length > 0);
    return indexer != null ? GetIndexerPropertyInfo(source, returnType, indexesTypes, indexer.Name) : null;
}

Indexer properties returned from reflection have not null array returned from method GetIndexParameters. This way we can find name for all of indexer and then do more specific search for the one we really looking for. And end user of DelegatesFactory do not have to think about name of an indexer at all (which is good since indexers do not have names in C# code).

To complete subject about an indexers getters we need to check for propertyInfo variable and PropertyInfo.Get/SetMethod properties if they are not null. It should be done the same way as with properties.

if (propertyInfo?.GetMethod == null)
{
    return null;
}

 

Setters

Now we can jump to indexers setters. It is very similar situation like with setters for properties. First we use Action classes instead of Func, second we have one more parameter for value to set in indexer. That is all. For example, first IndexerGet method after conversion to IndexerSet looks like this.

public static Action<TSource, TIndex, TProperty> IndexerSet<TSource, TIndex, TProperty>()
{
    var sourceType = typeof(TSource);
    var propertyInfo = GetIndexerPropertyInfo(sourceType, typeof(TProperty), new[] { typeof(TIndex) });
    return (Action<TSource, TIndex, TProperty>)
        propertyInfo?.SetMethod?.CreateDelegate(typeof(Action<TSource, TIndex, TProperty>));
}

Methods for 2D and 3D indexers are also very similar.

public static Action<TSource, TIndex, TIndex2, TReturn> IndexerSet<TSource, TReturn, TIndex, TIndex2>()
{
    var propertyInfo = GetIndexerPropertyInfo(typeof(TSource), typeof(TReturn), new[] { typeof(TIndex), typeof(TIndex2) });
    return (Action<TSource, TIndex, TIndex2, TReturn>)
            propertyInfo?.SetMethod?.CreateDelegate(typeof(Action<TSource, TIndex, TIndex2, TReturn>));
}

public static Action<TSource, TIndex, TIndex2, TIndex2, TReturn> IndexerSet<TSource, TReturn, TIndex, TIndex2, TIndex3>()
{
    var propertyInfo = GetIndexerPropertyInfo(typeof(TSource), typeof(TReturn), new[] { typeof(TIndex), typeof(TIndex2), typeof(TIndex3) });
    return (Action<TSource, TIndex, TIndex2, TIndex2, TReturn>)
            propertyInfo?.SetMethod?.CreateDelegate(
                typeof(Action<TSource, TIndex, TIndex2, TIndex2, TReturn>));
}

With method with array of indexes it is a little more complicated.

public static Action<object, object[], object> IndexerSet(this Type source, Type returnType, params Type[] indexTypes)
{
    var propertyInfo = GetIndexerPropertyInfo(source, returnType, indexTypes);
    if (propertyInfo?.SetMethod == null)
    {
        return null;
    }
    var sourceObjectParam = Expression.Parameter(typeof(object));
    var indexesParam = Expression.Parameter(typeof(object[]));
    var valueParam = Expression.Parameter(typeof(object));
    var paramsExpression = new Expression[indexTypes.Length + 1];
    for (var i = 0; i < indexTypes.Length; i++)
    {
        var indexType = indexTypes[i];
        paramsExpression[i] = Expression.Convert(Expression.ArrayIndex(indexesParam, Expression.Constant(i)), indexType);
    }
    paramsExpression[indexTypes.Length] = Expression.Convert(valueParam, returnType);
    Expression returnExpression =
        Expression.Call(Expression.Convert(sourceObjectParam, source), propertyInfo.SetMethod, paramsExpression);
    return (Action<object, object[], object>)Expression.Lambda(
        returnExpression, sourceObjectParam, indexesParam, valueParam).Compile();
}

First difference is of course Action instead of Func. Second is that returnType param is used in Expression.Convert to change type of valueParam parameter, which is last parameter of Expression.Call.

var valueParam = Expression.Parameter(typeof(object));
paramsExpression[indexTypes.Length] = Expression.Convert(valueParam, returnType)

The same valueParam variable is passed as last parameter (after array of indexes) of Expression.Lambda method. Everything else is similar to code in PropertyGet, PropertySet and IndexerGet.

With extension methods changes are in new DelegateIndexerSet method.

public static Delegate DelegateIndexerSet(Type source, Type returnType,
    params Type[] indexTypes)
{
    var propertyInfo = GetIndexerPropertyInfo(source, returnType, indexTypes);
    if (propertyInfo?.SetMethod == null)
    {
        return null;
    }
    var sourceObjectParam = Expression.Parameter(typeof(object));
    var valueParam = Expression.Parameter(returnType);
    var indexExpressions = new ParameterExpression[indexTypes.Length];
    for (var i = 0; i < indexTypes.Length; i++)
    {
        var indexType = indexTypes[i];
        indexExpressions[i] = Expression.Parameter(indexType);
    }
    var callArgs = indexExpressions.Concat(new [] { valueParam }).ToArray();
    var paramsExpressions = new[] { sourceObjectParam }.Concat(callArgs);
    return Expression.Lambda(
                Expression.Call(Expression.Convert(sourceObjectParam, source),
                    propertyInfo.SetMethod, callArgs), paramsExpressions).Compile();
}

Of course there is SetMethod used instead of getter equivalent. Also there is new variable valueParam as in method above. And new collections, callArgs and paramesExpressions, that allows us to pass appropriate values to lamba and setter calls. First one, is collection of indexes parameters expressions and value expression. Second one is source instance parameter expression, the same indexes expressions, and value parameter at the end.

And finally we can write last of IndexerSet methods with new DelegateIndexerSet method.

public static Action<object, TIndex, TReturn> IndexerSet<TReturn, TIndex>(this Type source)
{
    var indexType = typeof(TIndex);
    return (Action<object, TIndex, TReturn>)DelegateIndexerSet(source, typeof(TReturn), indexType);
}

public static Action<object, TIndex, TIndex2, TReturn> IndexerSet<TReturn, TIndex, TIndex2>(this Type source)
{
    var indexType = typeof(TIndex);
    var indexType2 = typeof(TIndex2);
    return (Action<object, TIndex, TIndex2, TReturn>)DelegateIndexerSet(source, typeof(TReturn), indexType, indexType2);
}

public static Action<object, TIndex, TIndex2, TIndex3, TReturn> IndexerSet<TReturn, TIndex, TIndex2, TIndex3>(this Type source)
{
    var indexType = typeof(TIndex);
    var indexType2 = typeof(TIndex2);
    var indexType3 = typeof(TIndex3);
    return (Action<object, TIndex, TIndex2, TIndex3, TReturn>)DelegateIndexerSet(source, typeof(TReturn), indexType, indexType2, indexType3);
}

Those methods are called exactly the same as the ones for get accessors. They just create different delegates.

var is1 = DelegateFactory.IndexerSet<TestClass, int, int>();
var is2 = DelegateFactory.IndexerSet<TestClass, int, int, int>();
var is3 = DelegateFactory.IndexerSet<TestClass, int, int, int, int>();
var is4 = Type.IndexerSet(typeof(int), typeof(int), typeof(int), typeof(int));
var is5 = Type.IndexerSet<int, int>();
var is6 = Type.IndexerSet<int, int, int>();
var is7 = Type.IndexerSet<int, int, int, int>();

is1(TestInstance, 0, 1);
is2(TestInstance, 0, 0, 1);
is3(TestInstance, 0, 0, 0, 1);
is4(TestInstance, new object[] { 0, 0, 0 }, 1);
is5(TestInstance, 1, 2);
is6(TestInstance, 0, 0, 2);
is7(TestInstance, 0, 0, 0, 2);

 

Static Fields

We have properties and indexers covered. Now we should try to make delegates for fields. First the static ones. How to do it? With properties (or methods for that matter) we have MethodInfo objects for each accessor, but fields are fields and they do not have accessor, which are really only methods with special name. Because of that we cannot create delegates from FieldInfo returned from reflection. We can do that only by creating delegates from expressions. There is Expression.Field exactly for that kind of data access.

But before implementing any of new methods. It is about time to write some test static fields.

public static string StaticPublicField = "StaticPublicField";

public static string StaticInternalField = "StaticInternalField";

public static string StaticProtectedField = "StaticProtectedField";

public static string StaticPrivateField = "StaticPrivateField";

 

Get static field value

New methods for creating delegates that will return value of a static field will be called StaticFieldGet. First we will write overload that take type as type param - for known types at compile time. They will be called in following way.

var sfg1 = DelegateFactory.StaticFieldGet<TestClass, string>("StaticPublicField");

Simplest implementation would look like below.

public static Func<TField> StaticFieldGet<TSource, TField>(string fieldName)
{
    var source = typeof(TSource);
    var lambda = Expression.Lambda(Expression.Field(null, source, fieldName));
    return (Func<TField>)lambda.Compile();
}

Much simpler in contrast to some indexer expressions for delegates. In lambda statement the same expression is even more clear.

Func<string> @delegate = () => TestClass.StaticPublicField;

Simple function that returns value. Ok, but what will happen if field name is invalid? Expression will fail and application will crash. With code like that we can't really remedy this in any way beside try-catch statement. Luckily there is another overload of Expression.Field method that takes FieldInfo object instead of a string with field name. We can search for desired field ourselves. If field is not found and FieldInfo object is null, null value will be returned instead of a delegate from StaticFieldGet method. To retrieve field data we can create new method GetFieldInfo based on code from GetPropertyInfo method.

private static FieldInfo GetStaticFieldInfo(Type source, string fieldName)
{
    var fieldInfo = (source.GetField(fieldName, BindingFlags.Static) ??
                          source.GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic)) ??
source.GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); return fieldInfo; }

And now we can write safer method using field info.

public static Func<TField> StaticFieldGet<TSource, TField>(string fieldName)
{
    var fieldInfo = GetStaticFieldInfo(typeof(TSource), fieldName);
    if (fieldInfo != null)
    {
        var lambda = Expression.Lambda(Expression.Field(null, fieldInfo));
        return (Func<TField>)lambda.Compile();
    }
    return null;
}

There is null check and another overload of Expression.Field method with field data as parameter. Rest of the code was already covered in different methods.

We can also test both methods for performance difference if pure expression version would be renamed to i.e. StaticFieldGetExpr.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < 10000; i++)
{
    DelegateFactory.StaticFieldGet<TestClass, string>("StaticPublicField");
}
_stopWatch.Stop();
Console.WriteLine("Static public field creator via reflection: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < 10000; i++)
{
    DelegateFactory.StaticFieldGetExpr<TestClass, string>("StaticPublicField");
}
_stopWatch.Stop();
Console.WriteLine("Static public field creator via expression: {0}", _stopWatch.ElapsedMilliseconds);

According to performance test, the difference is either negligible or with small indication of reflection one as faster.

Static public field creator via reflection: 538
Static public field creator via expression: 640

But again, what if we do not have either source type or field type or even both? After all fields are almost always private and can have private types.

As before we can fix that by adding new overloads.

var sfg1 = Type.StaticFieldGet<string>("StaticPublicField");
var sfg2 = Type.StaticFieldGet("StaticPublicField");

The same as with properties and indexers, first overload should return field type and second just object.

public static Func<TField> StaticFieldGet<TField>(this Type source,
    string fieldName)
{
    var fieldInfo = GetStaticFieldInfo(source, fieldName);
    if (fieldInfo != null)
    {
        var lambda = Expression.Lambda(Expression.Field(null, fieldInfo));
        return (Func<TField>)lambda.Compile();
    }
    return null;
}

public static Func<object> StaticFieldGet(this Type source, string fieldName)
{
    var fieldInfo = GetStaticFieldInfo(source, fieldName);
    if (fieldInfo != null)
    {
        Expression returnExpression = Expression.Field(null, fieldInfo);
        if (!fieldInfo.FieldType.IsClass)
        {
            returnExpression = Expression.Convert(returnExpression, typeof(object));
        }
        var lambda = Expression.Lambda(returnExpression);
        return (Func<object>)lambda.Compile();
    }
    return null;
}

If field have value type conversion to object is performed. Beside that it is almost the same code as in previous overload. Because of, that previous method can be simplified like this.

public static Func StaticFieldGet<TSource, TField>(string fieldName)
{
    var source = typeof(TSource);
    return source.StaticFieldGet(fieldName);
}

Now, in the same and easy manner we can retrieve fields with all visibilities.

var sfg3 = Type.StaticFieldGet<string>("StaticPublicField");
var sfg4 = Type.StaticFieldGet<string>("StaticInternalField");
var sfg5 = Type.StaticFieldGet<string>("StaticProtectedField");
var sfg6 = Type.StaticFieldGet<string>("StaticPrivateField");

Console.WriteLine("Static public field value: {0}", sfg3());
Console.WriteLine("Static internal field value: {0}", sfg4());
Console.WriteLine("Static protected field value: {0}", sfg5());
Console.WriteLine("Static private field value: {0}", sfg6());

After running this in test console application we will set correct values of all fields.

Static public field value: StaticPublicField
Static internal field value: StaticInternalField
Static protected field value: StaticProtectedField
Static private field value: StaticPrivateField

 

Set static field value

We now have a way to retrieve values of static fields. What about possibility of changing them? It can be done and as before with properties and indexers. Most of the code stays the same. Of course returned delegates would be of Action class. There is still Expression.Field in play, but need to be combined with Expression.Assign to be able to change field value with assignment operation.

For retrieving fields values we had three methods: static, extension method with type of field and extension method that returns an object. For changing fields we will write also three overloads.

var sfs1 = DelegateFactory.StaticFieldSet<TestClass, string>("StaticPublicField");
var sfs2 = Type.StaticFieldSet<string>("StaticPublicField");
var sfs3 = Type.StaticFieldSet("StaticPublicField");

Since first one can be easily rewritten as proxy to second one, let's start implementation with second one.

public static Action<TField> StaticFieldSet<TField>(this Type source,
    string fieldName)
{
    var fieldInfo = GetStaticFieldInfo(source, fieldName);
    if (fieldInfo != null)
    {
        var valueParam = Expression.Parameter(typeof(TField));
        var lambda = Expression.Lambda(typeof(Action<TField>),
            Expression.Assign(Expression.Field(null, fieldInfo), valueParam), valueParam);
        return (Action<TField>)lambda.Compile();
    }
    return null;
}

As you can see most of a change is in expression itself since there is not a single call to Expression.Field, but it is nested in Expression.Assign to mark that lambda body assign value parameter to field. Of course produced delegate is Action not a Func. For TestClass.StaticPublicField field it would produce lambda like below.

Action<string> @delegate = v => TestClass.StaticPublicField = v;

First overload will look like this.

public static Action<TField> StaticFieldSet<TSource, TField>(string fieldName)
{
    var source = typeof(TSource);
    return source.StaticFieldSet<TField>(fieldName);
}

Third one is much more interesting, but still nothing really hard to understand after indexers.

public static Action<object> StaticFieldSet(this Type source,
    string fieldName)
{
    var fieldInfo = GetStaticFieldInfo(source, fieldName);
    if (fieldInfo != null)
    {
        var valueParam = Expression.Parameter(typeof(object));
        var convertedValueExpr = Expression.Convert(valueParam, fieldInfo.FieldType);
        var lambda = Expression.Lambda(typeof(Action<object>),
            Expression.Assign(Expression.Field(null, fieldInfo), convertedValueExpr), valueParam);
        return (Action<object>)lambda.Compile();
    }
    return null;
}

As expected value parameter expression is in this method of type object instead of the same type as field. Because of that it needs to be converted first, before assignment. The same delegate as lambda for TestClass.StaticPublicField would be similar to lambda below.

Action<object> @delegate = v => TestClass.StaticPublicField = (string)v;

Time to test if those methods works.

var sfs1 = DelegateFactory.StaticFieldSet<TestClass, string>("StaticPublicField");
var sfs2 = Type.StaticFieldSet<string>("StaticPublicField");
var sfs3 = Type.StaticFieldSet("StaticPublicField");

sfs1("test1");
Console.WriteLine("Static public field value: {0}", TestClass.StaticPublicField);
sfs2("test2");
Console.WriteLine("Static public field value: {0}", TestClass.StaticPublicField);
sfs3("test3");
Console.WriteLine("Static public field value: {0}", TestClass.StaticPublicField);

Above code will result with console output as below.

Static public field value: test1
Static public field value: test2
Static public field value: test3

 

 

Fields

We already practiced on static fields so instance fields should not be a problem. Main change is extra parameter in all delegates. Because of that we need not null first parameter (source instance) in Expression.Field call. Beside that everything stays the same.

We should add some fields first to TestClass type.

public string PublicField;

internal string InternalField;

protected string ProtectedField;

private string _privateField;

public TestClass()
{
    PublicField = "PublicField";
    InternalField = "InternalField";
    ProtectedField = "ProtectedField";
    _privateField = "_privateField";
}

 

Get field value delegates

 Of course we want the same three methods for instance fields.

var fg1 = DelegateFactory.FieldGet<TestClass, string>("PublicField");
var fg2 = Type.FieldGet<string>("PublicField");
var fg3 = Type.FieldGet("PublicField");

First we have to create similar method to obtain FieldInfo object like in GetStaticFieldInfo.

private static FieldInfo GetFieldInfo(Type source, string fieldName)
{
    var fieldInfo = (source.GetField(fieldName) ??
                          source.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic)) ??
                          source.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    return fieldInfo;
}

Almost the same but it use Instance value of BindingFlags enumeration instead of Static one.

Let's start with last one FieldGet method this time - it should be most complex.

public static Func<object, object> FieldGet(this Type source, string fieldName)
{
    var fieldInfo = GetFieldInfo(source, fieldName);
    if (fieldInfo != null)
    {
        var sourceParam = Expression.Parameter(typeof(object));
        Expression returnExpression = Expression.Field(Expression.Convert(sourceParam, source), fieldInfo);
        if (!fieldInfo.FieldType.IsClass)
        {
            returnExpression = Expression.Convert(returnExpression, typeof(object));
        }
        var lambda = Expression.Lambda(returnExpression, sourceParam);
        return (Func<object, object>)lambda.Compile();
    }
    return null;
}

It is similar code to PropertyGet method and StaticFieldGet. Returned Func takes instance to retrieve field as object cast it to correct instance type and retrieves field value, which is casted to object if it is value type i.e. for TestClass.PublicField it will create delegate like this.

Func<object, object> @delegate = i => ((TestClass)i).PublicField;

Now, the same method can create delegate for two other methods just by safe cast.

public static Func<TSource, TField> FieldGet<TSource, TField>(string fieldName)
{
    var source = typeof(TSource);
    return source.FieldGet(fieldName) as Func<TSource, TField>;
}

public static Func<object, TField> FieldGet<TField>(this Type source,
    string fieldName)
{
    return source.FieldGet(fieldName) as Func<object, TField>;
}

I do not really investigate it further why this works (for example with ILDASM application) but I suspect that excessive casting get optimized by JIT compilation, because there is not really performance difference between produced delegates.

We can test new methods by following lines in test console application.

var fg1 = DelegateFactory.FieldGet<TestClass, string>("PublicField");
var fg2 = DelegateFactory.FieldGet<TestClass, string>("InternalField");
var fg3 = DelegateFactory.FieldGet<TestClass, string>("ProtectedField");
var fg4 = DelegateFactory.FieldGet<TestClass, string>("_privateField");

var fg5 = Type.FieldGet<string>("PublicField");
var fg6 = Type.FieldGet("PublicField");

Console.WriteLine("Public field value: {0}", fg1(TestInstance));
Console.WriteLine("Internal field value: {0}", fg2(TestInstance));
Console.WriteLine("Protected field value: {0}", fg3(TestInstance));
Console.WriteLine("Private field value: {0}", fg4(TestInstance));
Console.WriteLine("Public field value by object and field type: {0}", fg5(TestInstance));
Console.WriteLine("Public field value by objects: {0}", fg6(TestInstance));

It will produce following output in Windows console.

Public field value: PublicField
Internal field value: InternalField
Protected field value: ProtectedField
Private field value: _privateField
Public field value by object and field type: PublicField
Public field value by objects: PublicField

We can also test performance difference between direct field access and by proxy delegate.

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = TestInstance.PublicField;
}
_stopWatch.Stop();
Console.WriteLine("Public field directly: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = fg1(TestInstance);
}
_stopWatch.Stop();
Console.WriteLine("Public field retriever: {0}", _stopWatch.ElapsedMilliseconds);

var fieldInfo = Type.GetField("PublicField");
_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    var test = fieldInfo.GetValue(TestInstance);
}
_stopWatch.Stop();
Console.WriteLine("Public field via reflection: {0}", _stopWatch.ElapsedMilliseconds);

This performance test will produce similar result.

Public field directly: 257
Public field retriever: 545
Public field via reflection: 9721

As you can see difference is huge - more than 100%. But after all accessing public fields do not make sense this way, unless you do not know type at compilation time or field is not public at all. In those cases it is better to have slower access but access nevertheless. Unless you are fine with even bigger performance difference with use of reflection which is about 20 times slower.

 

Set field value delegates

Since we already trained setting of values in properties and in static fields, setting values in instance fields should not be a problem.

We still want the similar three methods: static, extension by objects and extension with field type.

var fs1 = DelegateFactory.FieldSet2<TestClass, string>("_privateField");
var fs2 = Type.FieldSet<string>("_privateField");          
var fs3 = Type.FieldSet("PublicField");

 Ok this time we again will start with last one that should be more complex. First two should be able to cast delegate from third.

public static Action<object, object> FieldSet(this Type source, string fieldName)
{
    var fieldInfo = GetFieldInfo(source, fieldName);
    if (fieldInfo != null)
    {
        var sourceParam = Expression.Parameter(typeof(object));
        var valueParam = Expression.Parameter(typeof(object));
        var convertedValueExpr = Expression.Convert(valueParam, fieldInfo.FieldType);
        Expression returnExpression = Expression.Assign(Expression.Field(Expression.Convert(sourceParam, source), fieldInfo), convertedValueExpr);
        if (!fieldInfo.FieldType.IsClass)
        {
            returnExpression = Expression.Convert(returnExpression, typeof(object));
        }
        var lambda = Expression.Lambda(typeof(Action<object, object>),
            returnExpression, sourceParam, valueParam);
        return (Action<object, object>)lambda.Compile();
    }
    return null;
}

As with instance properties we have delegate in form of an Action with two parameters: first instance and then value to set. Both as objects. Similarly to static field we assigning value to field by Expressio.Assign and Expression.Field. Field have to take converted source parameter to instance type, instead of a null like in static field. Beside that code is very similar. Two other methods can be implemented by simple cast as in FieldGet.

public static Action<object, TProperty> FieldSet<TProperty>(this Type source, string fieldName)
{
    return source.FieldSet(fieldName) as Action<object, TProperty>;
}

public static Action<TSource, TProperty> FieldSet<TSource, TProperty>(string fieldName)
{
    return typeof(TSource).FieldSet(fieldName) as Action<TSource, TProperty>;
}

It works, but according to tests it is a bit slower than specific implementation. Version with delegate created directly, without casting are as follows.

public static Action<object, TProperty> FieldSet2<TProperty>(this Type source, string fieldName)
{
    var fieldInfo = GetFieldInfo(source, fieldName);
    if (fieldInfo != null)
    {
        var sourceParam = Expression.Parameter(typeof(object));
        var valueParam = Expression.Parameter(typeof(TProperty));
        var te = Expression.Lambda(typeof(Action<object, TProperty>),
            Expression.Assign(Expression.Field(Expression.Convert(sourceParam, source), fieldInfo), valueParam),
            sourceParam, valueParam);
        return (Action<object, TProperty>)te.Compile();
    }
    return null;
}

public static Action<TSource, TProperty> FieldSet2<TSource, TProperty>(string fieldName)
{
    var source = typeof(TSource);
    var fieldInfo = GetFieldInfo(source, fieldName);
    if (fieldInfo != null)
    {
        var sourceParam = Expression.Parameter(source);
        var valueParam = Expression.Parameter(typeof(TProperty));
        var te = Expression.Lambda(typeof(Action<TSource, TProperty>),
            Expression.Assign(Expression.Field(sourceParam, fieldInfo), valueParam),
            sourceParam, valueParam);
        return (Action<TSource, TProperty>)te.Compile();
    }
    return null;
}

Code for performance test, that led to this conclusion, looks like this.

var fs1 = DelegateFactory.FieldSet<TestClass, string>("PublicField");
var fs2 = DelegateFactory.FieldSet2<TestClass, string>("PublicField");

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    fs1(TestInstance, "test");
}
_stopWatch.Stop();
Console.WriteLine("Public field set retriever with cast: {0}", _stopWatch.ElapsedMilliseconds);

_stopWatch = new Stopwatch();
_stopWatch.Start();
for (var i = 0; i < _delay; i++)
{
    fs2(TestInstance, "test");
}
_stopWatch.Stop();
Console.WriteLine("Public field set retriever without cast: {0}", _stopWatch.ElapsedMilliseconds);

Which will result in text below.

Public field set retriever with cast: 751
Public field set retriever without cast: 475

As you can see difference is noticeable. Probably instead of using the same method, but with parameter casting/without casting, correct delegate is created by creating new method that casts/converts parameters to appropriate types.

Ok, we will use FieldSet2 methods and not FieldSet overloads but after renaming then to FieldSet and FieldSetWithCast accordingly.

 

Improvements

If you were wondering about readonly keyword in fields it is a good thing. This thing should be covered in similar way like null check for getter or setter method in properties. After all readonly field is a similar to get-only property. Is there a way find out if field is declared with readonly keyword? As you surely remember readonly fields can be either set in field declaration or in constructor. Both ways are executed on object initialization. And on FieldInfo object is property called IsInitOnly which indicate if field can be set anytime or just during initialization - which another way of telling if field is readonly. This means that instead of just null check in fieldInfo variable we also need to check for this property. In both static fields and instance fields.

if (fieldInfo != null && !fieldInfo.IsInitOnly)

Of course it is needed in all StaticFieldSet and FieldSet methods  i.e.

public static Action<object, TProperty> FieldSet<TProperty>(this Type source, string fieldName)
{
    var fieldInfo = GetFieldInfo(source, fieldName);
    if (fieldInfo != null && !fieldInfo.IsInitOnly)
    {
        var sourceParam = Expression.Parameter(typeof(object));
        var valueParam = Expression.Parameter(typeof(TProperty));
        var te = Expression.Lambda(typeof(Action<object, TProperty>),
            Expression.Assign(Expression.Field(Expression.Convert(sourceParam, source), fieldInfo), valueParam),
            sourceParam, valueParam);
        return (Action<object, TProperty>)te.Compile();
    }
    return null;
}

 

Summary

Now we have a way to retrieve data from types by fields and properties, both static and instance. We also covered indexers which are special instance properties. What is left are events (instance not static), methods and constructors. Those types of members will be covered in next article.

Code for article can be found on github.



ViewFactory for Xamarin application

clock July 9, 2016 08:37 by author n.podbielski

First things first - Why?

First of all I do not like how creating of views and navigation works in Xamarin.

There is much boilerplate needed to just navigate from one page to another.

Typically like in Xamarin documentation we have to obtain INavigation interface instance, create instance of a new page, create instance of view model and all dependencies it requires.

When you page do not require view model things are real easy and Xamarin sample is just enough.

await Navigation.PushAsync(new LoginPage());

Right?! Easy! You want to use this framework because it so intuitive! Smile

When your page do not require sophisticated initialization nor view model have dependencies things are easy too.

await Navigation.PushAsync(new LoginPage(){ BindingContext = new LoginViewModel() });

Yes, it is possible to create view model instance via Xaml of course.

<Page.BindingContext>
    <LoginViewModel />
</Page.BindingContext>

And this is why you should never do that:

  1. Xaml intellisense is quite poor currently (as far as I know because I am using R#, which takes care of most of that)
  2. It is possible to write bad Xaml and you will NOT have any compile-time errors (and you are using strongly typed language, C# just for that, to get that kind of feedback). Those errors can be caught much later, in test or if view is rarely used, it can even travel to end user.
  3. Since you will not get any errors, you will have to specifically remember to add parameters, or other type of view model initialization. Did you ever tried to add constructor parameters to Xaml? It is possible, but complicated and I do not understand why would anyone tried that if this can be done easier and safer in code.

 

We should do it in code then.

When your view model have some dependencies (only 2 is not that much really) things becomes looks ugly.

await Navigation.PushAsync(new LoginPage()
    {
          BindingContext = new LoginViewModel(){
              AuthorizationService = new AutorizationService(new WebService(), new DataBase());
          };
    }
);

What if you navigate to the same page from more than one place? Do you create static method? It is viable solution to move view model creation to view constructor for example. Then, you could write only one line, like in example from Xamarin documentation, each time you want to navigate to this page. But still, if you have set of services and some of them are singletons, you will have to obtain instance of each of them in view or view model (much better) and change of dependencies will require few lines more. Lines that you probably wrote someplace else already. If you are lazy, like me, you probably do not want to repeat yourself. Smile

Of course in official documentation in samples INavigation instance is taken from VisualElement.Navigation, but if you need to pass some parameters between pages (simplest example is to pass customer instance from previous page with list of customers, to show details of this customer in next one) this solution becomes problematic. If you bind some data to view model and want to pass it to next one, you will need to obtain that data by casting BindingContext to appropriate type, create next view model instance and set required data to it.

await Navigation.PushAsync(new MainPage()
    {
          BindingContext = new MainViewModel(){
              User = ((LoginViewModel)BindingContext).Login,
              DataBase = new DataBase(),
              GPSService = new GPSService(),
              CameraService = new CameraService(),
          };
    }
);

This is just to show problems with navigation implemented like that.

There is really simple solution to dependencies problem. It is widely used and called IoC. With container, you can create view models and set dependencies via constructor or properties. It also perfectly doable to use IoC container to obtain view model dependencies in view or in view model constructor. But again it is bad practice. IoC container should be (in ideal world) used once, for example to create first view and then work in background. Having that in mind view is not best place to use it, since Xaml requirement is, that views do not have parameters in constructors. View model it is then.

 

What would be better

Best way to navigate between views in view models is in my opinion one line with one method

Navigate<MainViewModel>();

And if you need special initialization or passed parameters from previous view model:

Navigate<MainViewModel>((mvm)=>mvm.User = Login);

Would you not agree, that this looks much nicer?

But how to do that? Of course best solution is for Navigate method to do all the initialization of view and view model, setting BindingContext to view model and pushing it to INavigation instance. Overload with action would do extra initialization of new view model.

  1. Obtain correct view for given view model type.
  2. Create view instance.
  3. Create view model instance and get all its dependencies from IoC.
  4. Set view model in view
  5. Set new view to Master page if necessary.
  6. Obtain INavigation instance and push newly created view on top of that.

 

In this article we will cover first two points, fourth and partially third one. If you are wondering what Master page is all about, you should read my previous article. In summary: we want seamless views creation and navigation between them, regardless if there are only detail views (with menu, top bar, bottom status bar etc.) or whole screen views (without menu, top bar, bottom status bar etc.). Rest will be covered in next article.

 

Implementation of ViewFactory

To ease our start with new application we can reuse some code from Master page article. This code is available on github.

To show creation of ordinary pages and detail pages, main application need only two menu items, two views and application file. We can start by creating ViewFactory shared xamarin project and add files from previous article, with just little changes.

 

File App.xaml have almost the same content as before.

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ViewFactory.App">
</Application>

Code file App.xaml.cs is very similar too.

using CustomMasterDetailControl;

namespace ViewFactory
{
    public partial class App
    {
        public App()
        {
            InitializeComponent();
            MainPage = MasterDetailControl.Create<MasterDetail, MasterDetailViewModel>();
        }
    }
}

Detail.xaml and MasterDetail.xaml are almost the same as Detail1.xaml and MasterDetail from previous article, respectively.

<?xml version="1.0" encoding="utf-8" ?>
<customMasterDetailControl:DetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                                  xmlns:customMasterDetailControl="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
                                  x:Class="ViewFactory.Detail">
    <Label Text="Detail" VerticalOptions="Center" HorizontalOptions="Center" />
</customMasterDetailControl:DetailPage>
<?xml version="1.0" encoding="utf-8" ?>
<customMasterDetailControl:DetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                                  xmlns:customMasterDetailControl="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
                                  x:Class="ViewFactory.Detail">
    <Label Text="Detail" VerticalOptions="Center" HorizontalOptions="Center" />
</customMasterDetailControl:DetailPage>

MasterDetailViewModel have only two commands to navigate to detail page and ordinary page. For now it just creates and set both pages as detail views, but we will change that after implementing ViewFactory class.

using System.Windows.Input;
using CustomMasterDetailControl;
using Xamarin.Forms;

namespace ViewFactory
{
    public class MasterDetailViewModel : MasterDetailControlViewModel
    {
        private ICommand _toDetai;

        private ICommand _toOrdinaryPage;

        public ICommand ToDetail
        {
            get { return _toDetai ?? (_toDetai = new Command(OnToDetail)); }
        }

        public ICommand ToOrdinaryPage
        {
            get { return _toOrdinaryPage ?? (_toOrdinaryPage = new Command(OnToOrdinaryPage)); }
        }

        private void OnToOrdinaryPage()
        {
            Detail = new OrdinaryPage();
        }

        private void OnToDetail()
        {
            Detail = new Detail();
        }
    }
}

OrdinaryPage derives from new UIPage class which serve as base class for DetailPage (base class of Detail page in Detail.xaml file). This way we can use one single base class for all of our views. It makes ViewFactory class a little simpler, but if it is impossible in your project, it will be simple enough to make this work with different one or even more than one base class for both types of views.

And OrdinaryPage also just have a single label inside.

<?xml version="1.0" encoding="utf-8" ?>
<masterDetail:UIPage xmlns="http://xamarin.com/schemas/2014/forms"
                         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                         xmlns:masterDetail="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
                         x:Class="ViewFactory.OrdinaryPage">
  <Label Text="Ordinary page" VerticalOptions="Center" HorizontalOptions="Center" />
</masterDetail:UIPage>

One last touch to make this first version work: we need to copy and change a little CustomMasterDetailControl project.

 

BaseViewModel class is exactly what it seems - it only have implementation of INotifyPropertyChanged interface and we will need this base class for all of our view models. It is used in MasterDetailControlViewModel class instead of standalone implementation.

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace CustomMasterDetailControl
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

MasterDetailControlViewModel class now derives from BaseViewModel.

public class MasterDetailControlViewModel : BaseViewModel, INavigation

UIPage as mentioned above will serve as base class for all views, both partial and for whole screen:

using Xamarin.Forms;

namespace CustomMasterDetailControl
{
    public class UIPage : ContentPage
    {
    }
}
namespace CustomMasterDetailControl
{
    public class DetailPage : UIPage
    {
        public DetailPage()
        {
            SideContentVisible = true;
        }

        public bool SideContentVisible { get; set; }
    }
}

Ok. Now we can implement ViewFactory class. First thing to do is to create relations between view model types and view types. To do that, we need to scan all types and find all views. We can do it in Init method of ViewFactory class.

public static void Init()
{
    var appAssebly = Assembly.GetExecutingAssembly();
    var pages = appAssebly.DefinedTypes.Where(t => t.IfHaveBaseClassOf<UIPage>());
    var viewModels = appAssebly.DefinedTypes.Where(t => t.IfHaveBaseClassOf<BaseViewModel>()).ToArray();
    foreach (var page in pages)
    {
        var viewModel = viewModels.FirstOrDefault(vm => vm.Name == page.Name + "Model");
        if (viewModel != null)
        {
            Views.Add(viewModel, new ViewData
            {
                IsDetail = page.IfHaveBaseClassOf<DetailPage>(),
                ViewModelType = viewModel,
                ViewType = page
            });
        }
    }
}

ViewData class is just really simple data object.

public class ViewData
{
    public Type ViewType { get; set; }
    public Type ViewModelType { get; set; }
    public bool IsDetail { get; set; }
}

What is IfHaveBaseClassOf method? It is just simple Type type extension method. Contains logic for searching all base types in inheritance tree, to check if any of them is the one we are looking for.

public static bool IfHaveBaseClassOf(this Type type) where TBase : class
{
    var haveBase = false;
    var typeToCheck = type;
    var baseType = typeof(TBase);
    while (typeToCheck != null)
    {
        if (typeToCheck.BaseType == baseType)
        {
            haveBase = true;
            break;
        }
        else
        {
            typeToCheck = typeToCheck.BaseType;
        }
    }
    return haveBase;
}

It takes some type and checks if any base type in tree of inheritance is of specified type we want to find. It allows us to go through every type in assembly and check if it derive from BaseViewModel or UIPage classes which both are needed for our ViewFactory. Oh, and there is a check if view is detail view (derive from DetailPage) also with this method.

With relations between views and view models we can implement method for creating views.

public UIPage CreateView<TViewModel>() where TViewModel : BaseViewModel
{
    return CreateView(typeof(TViewModel));
}

public UIPage CreateView(Type viewModelType)
{
    if (Views.ContainsKey(viewModelType))
    {
        var viewData = Views[viewModelType];
        var page = (UIPage)Activator.CreateInstance(viewData.ViewType);
        var viewModel = Activator.CreateInstance(viewModelType);
        page.BindingContext = viewModel;
        return page;
    }
    return null;
}

As you can see it is really simple. It takes either type parameter or parameter with view model type. Then it find view type and instantiate both via Activator class. With view model it can became somewhat problematic if it does have dependencies, but it can easily be changed with IoC container, which would resolve view model with dependencies. Last thing it does, is setting view model as binding context for view.

This is just enough to have first working application with this solution. With just small change to MasterDetailViewModel commands we can now navigate via view models instead of views.

public class MasterDetailViewModel : MasterDetailControlViewModel
{
    private readonly ViewFactory.ViewFactory _viewFactory;

    private ICommand _toDetai;

    private ICommand _toOrdinaryPage;

    public MasterDetailViewModel()
    {
        _viewFactory = new ViewFactory.ViewFactory();
    }

    public ICommand ToDetail
    {
        get { return _toDetai ?? (_toDetai = new Command(OnToDetail)); }
    }

    public ICommand ToOrdinaryPage
    {
        get { return _toOrdinaryPage ?? (_toOrdinaryPage = new Command(OnToOrdinaryPage)); }
    }

    private void OnToDetail()
    {
        Detail = _viewFactory.CreateView<DetailPage>();
    }

    private void OnToOrdinaryPage()
    {
        Navigation.PushAsync(_viewFactory.CreateView<OrdinaryPage>());
    }
}

After starting this application we will see something similar to this:

 

First button will take us to detail page (menu still will be visible) and second one will take us to page for whole screen (without menu).

 

Things to improve

But there are still few points for improvements:

  1. Faster type instantiation instead of Activator
  2. Use of views and view models from libraries
  3. Some views might need specific view model type
  4. We can disable reading of all or only specific assemblies

 

Faster Views creation

Instead of using Activator.CreateInstence it is a bit faster (according to this post on StackOverflow) to use Expression.Lambda. My tests proves that it is true and compiled expression is about 25% faster than Activator.CreateInstance method. To use that technic we need to create delegate for each view. It is also possible for view model but it would not be good idea for constructors with parameters (which is something we want to do but with IoC). Let us change a little Init method and ViewData class. In ViewData we just have to add property for creator delegate:

public Func Creator { get; set; }

We need to fill this property in Init method:

Creator = (Func<UIPage>)Expression.Lambda(Expression.New(page.GetConstructor(Type.EmptyTypes))).Compile(),

It is not completely safe code, since Expression.New method expects not null parameter and Type.GetConstructor method can return null, if there is no constructor specified with given parameters (in this particular case without parameters). However this will happed only when view do not have default parameterless constructor, which view should have anyway. Anyway, in such a case Activator.CreateInstance would throw error too.

 

External libraries

Sometimes we have views and view models in different assembly than application assembly. Obviously, we want to be able to navigate to those views too. It is very easy to handle them with small change to our code. We only need to iterate through all of application assemblies and scan them as we do for application assembly. For this we can extract this scanning logic to new ScanAssembly method:

private static void ScanAssembly(Assembly appAssebly)
{
    var pages = appAssebly.DefinedTypes.Where(t => t.IfHaveBaseClassOf<UIPage>());
    var viewModels = appAssebly.DefinedTypes.Where(t => t.IfHaveBaseClassOf<BaseViewModel>()).ToArray();
    foreach (var page in pages)
    {
        var viewModel = viewModels.FirstOrDefault(vm => vm.Name == page.Name + "Model");
        if (viewModel != null)
        {
            Views.Add(viewModel, new ViewData
            {
                IsDetail = page.IfHaveBaseClassOf<DetailPage>(),
                ViewModelType = viewModel,
                ViewType = page,
                Creator =
                    (Func<UIPage>)Expression.Lambda(Expression.New(page.GetConstructor(Type.EmptyTypes))).Compile(),
            });
        }
    }
}

And we just need to iterate through all of assemblies in Init method.

var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
    ScanAssembly(assembly);
}

With this our ViewFactory will register all views for available view models in all of assemblies.

 

Overriding external views

But sometimes, if you have some library with predefined views and view models for them (for login page i.e.), you do not want to use default view and instead use other one that will be more suitable for application. It would be nice to be able to override those default views. Best way to do that, would be to create view with the same name in application assembly and let ViewFactory do the rest - scanning and overriding the default.

First, we have to modify a little our scanning method.

private static void ScanAssembly(Assembly appAssebly, bool @override = false)
{
    var pages = appAssebly.DefinedTypes.Where(t => t.IfHaveBaseClassOf<UIPage>());
    var viewModels = appAssebly.DefinedTypes.Where(t => t.IfHaveBaseClassOf<BaseViewModel>()).ToArray();
    foreach (var page in pages)
    {
        var viewModel = viewModels.FirstOrDefault(vm => vm.Name == page.Name + "Model");
        if (viewModel != null)
        {
            if (!Views.ContainsKey(viewModel))
            {
                Views.Add(viewModel, GetViewData(viewModel, page));
            }
        }
        //no view model in assembly and if app assembly -> override
        else if (@override)
        {
            var viewToOverride = Views.FirstOrDefault(kv => kv.Key.Name == page.Name + "Model");
            if (viewToOverride.Key != null)
            {
                Views[viewToOverride.Key] = GetViewData(viewToOverride.Value.ViewModelType, page);
            }
        }
    }
}

New else clause do exactly that. If view model is not found in assembly, and this assembly is main application assembly (override parameter is equal true), ViewFactory looks through its current registration list and override if there is already view model with name similar to view name.

Before last improvement (scanning only specific assemblies), we can test other, new features.

We can create new PCL project named ExternalAssembly with ExternalView, ToOverrideView and appropriate view models for them.

 

In ExternalView and ToOverrideView files we have following content:

<?xml version="1.0" encoding="utf-8" ?>
<customMasterDetailControl:DetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                                  xmlns:customMasterDetailControl="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
                                  x:Class="ExternalAssembly.ExternalView">
    <Label Text="External page" VerticalOptions="Center" HorizontalOptions="Center"
           FontSize="40"/>
</customMasterDetailControl:DetailPage>
<?xml version="1.0" encoding="utf-8" ?>
<customMasterDetailControl:DetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                                  xmlns:customMasterDetailControl="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
                                  x:Class="ExternalAssembly.ToOverrideView">
    <Label Text="Not overriden view" VerticalOptions="Center" HorizontalOptions="Center"
           FontSize="40"/>
</customMasterDetailControl:DetailPage>

Nothing really fancy - just a big labels with simple text, which is just enough to see if this works. View models for those views are just classes that derives from BaseViewModel.

For ViewFactory, to be able to see new project, we need to add reference to ViewFactory.Droid project. Also we need to add buttons to navigate to those new views and commands to handle them:

<Button Text="To external page" Command="{Binding ToExternalPage}" />
<Button Text="To overriden page" Command="{Binding ToOverridenPage}" />
private ICommand _toExternalPage;
private ICommand _toOverridenPage;

public ICommand ToExternalPage
{
    get { return _toExternalPage ?? (_toExternalPage = new Command(OnToExternal)); }
}

public ICommand ToOverridenPage
{
    get { return _toOverridenPage ?? (_toOverridenPage = new Command(OnToOverriden)); }
}

private void OnToExternal()
{
    Detail = _viewFactory.CreateView<ExternalViewModel>();
}

private void OnToOverriden()
{
    Detail = _viewFactory.CreateView<ToOverrideViewModel>();
}

After running this code and trying new buttons we will see something similar to following screenshots.

Now we should try to override ToOverrideView. To do that we need to create view with the same name in ViewFactory.Droid assembly.

<?xml version="1.0" encoding="utf-8" ?>
<customMasterDetailControl:DetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                                  xmlns:customMasterDetailControl="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
                                  x:Class="ViewFactory.ToOverrideView">
    <Label Text="Overriden view" VerticalOptions="Center" HorizontalOptions="Center"
           FontSize="40" />
</customMasterDetailControl:DetailPage>

It is almost the same as previous one with different label text. We just need to start an application and all the magic will happen automatically Smile. After clicking on last button (To overriden page) we will see different label this time.

 

 

We do not need all assemblies

Another point for improvements will be to disable scanning of all application assemblies. We don't need to scan System.Xml and other .NET dlls. One of the solutions would be to ignore those assemblies. It would not be hard to just skip them in ViewFactory, but still there are many libraries and Nuget packages that do not have views and they would be scanned anyway. To be true, there are much more assemblies without views in application than with views. Logical solution is then to look for assemblies with them to be scanned later. For example it is possible to add assembly attribute to mark assemblies with views for scanning. Simple one as below is enough.

using System;

namespace ViewFactory
{
    [AttributeUsage(AttributeTargets.Assembly)]
    public class ViewAssemblyAttribute : Attribute
    {
    }
}

But there is one problem. Since we need to mark i.e. ExternalAssembly as assembly with views we need this attribute to be accessible in this project. So we need third project with this attribute so we can reference it in ExternalAssembly. Even then new project with just a single attribute do not makes sense. Best thing would be to create new project with ViewFactory and other types it needs.
Unfortunately it is not that easy. Ideally it would be to place everything in PCL project, but portable version of .NET is very limited. There is no way to get list of assemblies, executing assembly, even acquiring base type of type is more complicated. There are two solutions we can use to get around those limitations.

  1. Split everything into PCL project and platform specific projects (with full .NET). Minus, big minus, of this solution is that you need to implement everything that requires full .NET more than once. But if you will write bigger framework for your applications you will do that at some point anyway, and if you have set of assemblies like that, you can do that very easily. IoC also makes this easier since you can create services for every specific part of .NET support that do not exists in PCL version (like IAdvancedReflection for part of reflection support that exists only in full .NET)
  2. Or you can try to remedy lacks of some properties or methods by combination of reflection, delegates, and expressions.

 

Since the first solution is really boring (and more easy, safe, testable etc.) we will cover second one first Smile. On aside note, it makes sense to use it only for single properties or methods. Writing bigger parts functionality like this would be really hard.

Remember TypesExtension class with single method IfHaveBaseClassOf? It wont work in PCL, without changes because portable .NET lacks Type.BaseType property. Oh, there is BaseType property, but on TypeInfo type. And TypeInfo have AsType method that returns corresponding Type object. But BaseType property returns Type value and there is need to cast it to TypeInfo again.

public static bool IfHaveBaseClassOf<TBase>(this Type type) where TBase : class
{
    var haveBase = false;
    var typeToCheck = type.GetTypeInfo();
    var baseType = typeof(TBase);
    while (typeToCheck != null)
    {
        if (typeToCheck.BaseType == baseType)
        {
            haveBase = true;
            break;
        }
        typeToCheck = typeToCheck.BaseType.GetTypeInfo();
    }
    return haveBase;
}

Ok, this is just juggling Type and TypeInfo, even if Type have BaseType property which is just unavailable in PCL. We could use reflection to get this property value.

var baseType = (Type)typeof(Type).GetRuntimeProperty("BaseType").GetValue(type);

But whole point of moving this to separate project was to make things faster, by reducing list of assemblies! This way, certainly, it would not become any faster. How we make it be better, then? We can make ourselves function to retrieve BaseType, the same way as we did with views constructors. There is even Expression.Property method just for that.

var parameterExpression = Expression.Parameter(typeof(Type));
GetBaseTypeFunc = (Func<Type, Type>)Expression.Lambda(Expression.Property(parameterExpression, "BaseType"), parameterExpression).Compile();

This creates delegate of function that takes Type object and returns its property BaseType. Parameter expression is used twice, because it is mentioned twice in lambda: first as parameter declaration and the as use. This may be a little confusing (at least was for me at first) so this is how this would be defined as 'usual' lambda.

(Type type)=>type.BaseType

According to my tests it is quicker than using portable .NET TypeInfo.AsType(), Type.GetTypeInfo() and TypeInfo.BaseType members. 1 million of executions of PCL version takes about 130ms against 110ms with use of delegate for getting BaseType value directly from Type. Not much of a difference, but since this method is used a lot it is worth a shot.

To cache this function we can save it to static field in static constructor.

static TypeExtensions()
{
    var parameterExpression = Expression.Parameter(typeof(Type));
    GetBaseTypeFunc = (Func<Type, Type>)Expression.Lambda(Expression.Property(
        parameterExpression, "BaseType"), parameterExpression).Compile();
}

And it is used exactly the same as BaseType property:

public static bool IfHaveBaseClassOf(this Type type) where TBase : class
{
    var haveBase = false;
    var typeToCheck = type;
    var baseType = typeof(TBase);
    while (typeToCheck != null)
    {
        if (GetBaseTypeFunc(typeToCheck) == baseType)
        {
            haveBase = true;
            break;
        }
        typeToCheck = GetBaseTypeFunc(typeToCheck);
    }
    return haveBase;
}

Ok. But this is only one missing property and code that mitigate this limitation is quite complex. Also code like that do not get checked at compile time. But splitting it in to PCL and platform specific implementations would be quite complex since it is static class and we cannot just make it abstract and override single method. Making it instance class would not make things easier too, since we can't use platform specific implementation directly in PCL. It would force us to write interface in PCL and then use its platform implementation via for example static reference in App class. This would be even more complex than compiling the delegate, and quite few things to do just to use one unavailable property. With solution as above we at least have it contained into one class and one file and we can forget about this inconvenience. It works and with few tests for this method it should be safe.

Splitting rest of classes between PCL and platform implementation will not be that complicated. TypeExtensions, ViewAssemblyAttribute, ViewData can be placed in PCL without changes. ViewFactory have to split into two parts. PCL version will be called BaseViewFactory and platform specific (like Android in sample) will be just ViewFactory.

There are two things that need platform specific implementation:

  1. Type.GetContstructor(Typep[]) method is not available in PCL
  2. AppDomain class is not available in PCL
  3. Assembly.GetExecutingAssembly method is not available in PCL

 

For first two we have to create abstract methods (and BaseViewFactory need to be abstract by extent).

protected abstract Assembly[] GetViewAssemblies();

protected abstract ConstructorInfo GetDefaultConstructor(Type page)

In platform version of ViewFactory we have:

public class ViewFactory : BaseViewFactory
{
    protected override Assembly[] GetViewAssemblies()
    {
        return AppDomain.CurrentDomain.GetAssemblies();
    }

    protected override ConstructorInfo GetDefaultConstructor(Type page)
    {
        return page.GetConstructor(Type.EmptyTypes);
    }
}

In summary it is the same code that was previously in single ViewFactory class, but now is called via abstract methods. Unfortunately calling those two method forces as to make Init method non static. And this forces us to make some static reference to ViewFactory in example in App class or use Singleton pattern. For case of sample simplicity static instance will suffice.

public partial class App
{
    public static readonly VF ViewFactory = new VF();
    public App()
    {
        InitializeComponent();
        ViewFactory.Init();
        MainPage = MasterDetailControl.CreateMainPage<MasterDetail, MasterDetailViewModel>();
        Navigation = MainPage.Navigation;
    }
}

As you can see it is just static global instance. Nothing fancy. IoC would allow us to make it much better.

Another problem with new code is that, since it do not reside in application assembly, we do not have easy access to it. Calling code like below in ViewFactory class (platform part):

Debug.WriteLine(Assembly.GetExecutingAssembly());
Debug.WriteLine(Assembly.GetCallingAssembly());
Debug.WriteLine(Assembly.GetEntryAssembly());

will give us following result:

[0:] ViewFactory.Android, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
[0:] ViewFactory, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
[0:]

First is Android platform version of ViewFactory project, second is PCL ViewFactory assembly, and third is null. Of course this assembly is inside loaded assemblies list and we could find it by App or MainAcitivity types, but we would have to iterate both: assemblies and types in each of them, and we wanted not to do that.
Simple way to solve this issue it to just call Assembly.GetExecutingAssembly() inside application assembly and pass return value to ViewFactory. Let us change Init method once again and pass appropriate value inside App type constructor.

public void Init(Assembly appAssembly)

ViewFactory.Init(Assembly.GetExecutingAssembly());

And this is why we do not need to fix lack of Assembly.GetExecutingAssembly method in PCL. We do not need to call it there anyway.

 

Non standard view model - view connection

It might be case when there is need to have connection between view model and view other than by name convention (or if this is just impossible to rename view or view model). For this case it would be nice to have possibility of defining view type. We can solve this by adding new attribute for view models, that allows us to define desired view type.

[AttributeUsage(AttributeTargets.Class)]
public class ViewTypeAttribute : Attribute
{
    public ViewTypeAttribute(Type viewType)
    {
        ViewType = viewType;
    }

    public Type ViewType { get; }
}

This attribute it is used like this:

[ViewType(typeof(NoViewModelView))]
public class NoViewViewModel : BaseViewModel

Very easy and convenient. But applying it to view model forces us to change ScanAssembly method a little, so it reads view models first and then tries to found appropriate views for them.

private void ScanAssembly(Assembly appAssebly, bool @override = false)
{
    var pages = appAssebly.DefinedTypes.Where(t => t.IfHaveBaseClassOf<UIPage>()).ToArray();
    var viewModels = appAssebly.DefinedTypes.Where(t => t.IfHaveBaseClassOf<BaseViewModel>());

    foreach (var viewModel in viewModels)
    {
        var viewTypeAttribute = viewModel.GetCustomAttribute<ViewTypeAttribute>();
        var page = viewTypeAttribute != null 
            ? viewTypeAttribute.ViewType 
            : pages.FirstOrDefault(p => p.Name == viewModel.Name.Replace(ViewModelPrefix, ""))?.AsType();
        if (page != null)
        {
            var asType = viewModel.AsType();
            if (!Views.ContainsKey(asType))
            {
                Views.Add(asType, GetViewData(asType, page));
            }
        }
    }
    //no view model in assembly and if app assembly -> override
    if (@override)
    {
        foreach (var page in pages)
        {
            var viewToOverride = Views.FirstOrDefault(kv => kv.Key.Name == page.Name + ViewModelPrefix);
            if (viewToOverride.Key != null)
            {
                Views[viewToOverride.Key] = GetViewData(viewToOverride.Value.ViewModelType, page.AsType());
            }
        }
    }
}

Its pretty much the same code, but instead of iterating pages we are iterating view models.

New logic involves looking for above attribute. Code is mostly self-explanatory. First its search for attribute on view model and if it was applied just uses type defined there. If not it searches inside collection of pages in assembly. Since Assembly.DefinedTypes is collection of TypeInfo objects null propagation and AsType method is used.

var viewTypeAttribute = viewModel.GetCustomAttribute<ViewTypeAttribute>();
        var page = viewTypeAttribute != null 
            ? viewTypeAttribute.ViewType 
            : pages.FirstOrDefault(p => p.Name == viewModel.Name.Replace(ViewModelPrefix, ""))?.AsType();

There are some cases when several views are connected to the same view model. It might be some kind of wizard or other process that require several steps and each step is represent by different view. To minimize effect of state on application (many bugs in my code, including ones that are really hard to debug where connected to state of objects, corrupted or otherwise incorrect, so I can agree to some extent when someone is using phrase: 'state is evil') it is good to have the same view model for all of those views. How to accomplish that with our view factory?

The easiest way to do it is to have overload of CreateView method that takes view model and view types. Yes, it defeats purpose of view factory to get rid of views in view models navigation code, but is makes code much more readable and intuitive. Otherwise we would have to create some kind of mechanism of selecting of view from view model state that is transparent to view factory. How? It would be possible with special view model type, with method or property, that would return desired type of view. But it would be too rigid to force base class of view models just for that. More flexible would be to possibility of defining method or property visible to view factory that would return view type. In both we would have to deal with view types anyway. I was considering for some time creating attributes for views that would allow us to define method or property name and desired value returned that would indicate, that it is time for this particular view. I think that it would be viable since view model probably would have some internal state value, that would point to some particular step (number of step for example). However it would force us to place view model method name in attribute which would be hard to maintain and not very transparent.
So the most reasonable way is to just allow to define view type for view model in CreateView method.

public UIPage CreateView<TViewModel, TView>() where TViewModel : BaseViewModel
    where TView : UIPage
{
    var type = typeof(TView);
    if (!_unconnectedViews.ContainsKey(type))
    {
        _unconnectedViews[type] = GetViewCreator(type);
    }
    return CreateView(typeof(TViewModel), _unconnectedViews[type]);
}

public UIPage CreateView<TViewModel, TView>(TViewModel viewModel) where TViewModel : BaseViewModel
    where TView : UIPage
{
    var type = typeof(TView);
    if (!_unconnectedViews.ContainsKey(type))
    {
        _unconnectedViews[type] = GetViewCreator(type);
    }
    return CreateView(viewModel, _unconnectedViews[type]);
}

Those two new overloads are used, first navigate to wizard view model and view type (overload with two types) and then navigate to all subsequent steps (overload with view model instance and view type).

Private static CreateView methods needs to be changed too.

private static UIPage CreateView(Type viewModelType, Func<UIPage> creator)
{
    var viewModel = Activator.CreateInstance(viewModelType);
    return CreateView(viewModel, creator);
}

private static UIPage CreateView(object viewModel, Func<UIPage> creator)
{
    var page = creator();
    page.BindingContext = viewModel;
    return page;
}

Now we can test both, new features in action. First custom connection between view and view models. For this we should create new view and view model.

<?xml version="1.0" encoding="utf-8" ?>
<customMasterDetailControl:DetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                                  xmlns:customMasterDetailControl="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
                                  x:Class="ViewFactorySample.View.NoViewModelView">
    <Label Text="No view model view" VerticalOptions="Center" HorizontalOptions="Center"
           FontSize="40"/>
</customMasterDetailControl:DetailPage>
[ViewType(typeof(NoViewModelView))]
public class NoViewViewModel : BaseViewModel
{

}

Nothing very different from previous views and view models. We need just to add new button in main view:

private ICommand _toCustomConnection;

public ICommand ToCustomConnection
{
    get { return _toCustomConnection ?? (_toCustomConnection = new Command(OnToCustomConnection)); }
}

private void OnToCustomConnection()
{
    Detail = _viewFactory.CreateView<NoViewViewModel>();
}
<Button Text="To custom connection page" Command="{Binding ToCustomConnection}" />

After running changed application and clicking on new button we will see page like below.

 

Custom connection created by attribute works.

Let's test navigating to views with the same view model.

For this we have to create new view model and (at least) two views. Second view is almost the same as previous ones (with different label text). First have one button more, to allow us to test navigation to second step.

<?xml version="1.0" encoding="utf-8" ?>
<customMasterDetailControl:DetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:customMasterDetailControl="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
             x:Class="ViewFactorySample.View.Step1View">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Text="Step 1" VerticalOptions="Center" HorizontalOptions="Center"
         FontSize="40" />
        <Button Grid.Row="1" Text="To next step" Command="{Binding ToNextStep}"></Button>
    </Grid>
</customMasterDetailControl:DetailPage>

ToNextStep command is handled in view model.

using System.Windows.Input;
using CustomMasterDetailControl;
using ViewFactorySample.View;
using Xamarin.Forms;

namespace ViewFactorySample.ViewModels
{
    public class WizardViewModel : BaseViewModel
    {
        private ICommand _toNextStep;

        public ICommand ToNextStep
        {
            get { return _toNextStep ?? (_toNextStep = new Command(OnToNextStep)); }
        }

        private void OnToNextStep()
        {
            var mainPage = ((NavigationPage)App.Current.MainPage).CurrentPage;
            var masterPageViewModel = (MasterDetailViewModel)mainPage.BindingContext;
            masterPageViewModel.Detail = masterPageViewModel.ViewFactory.CreateView<WizardViewModel, Step2View>(this);
        }
    }
}

As you can see command is pretty complicated, but almost all of the code is to retrieve reference to MasterPageViewModel to set new page as detail. This is major pain and I will cover in next article how to achieve easy and uniform navigation to ordinary, whole screen pages and detail ones.

Last thing to make this test works is new button on main page (exactly the same as before, with different text and command). It is handled a bit differently, to show how to create page with new CreateView overload.

private void OnToWizard()
{
    Detail = _viewFactory.CreateView<WizardViewModel, Step1View>();
}

After running application and using new menu button it will navigate to first step view. Button at bottom will then navigate to second step.

 

That is all. We have working ViewFactory class that allows us to create page - view model pairs in easily and configurable way. But as you can see from MasterDetailViewModel and WizardViewModel there are still some problems with navigation to whole screen pages and detail pages. Since code is different we need to know in two places if page is detail page or not. It is redundant since we already set that by choosing base class (UIPage or DetailPage). There is need for new mechanism that takes care of that - either set page to Detail property of MasterPage or push it to navigation. Also ViewFactory always creates view models with Activator.CreateInstance which require view model to have default, parameterless constructor. We do not want that, but to fix that we need IoC container to resolve view models with dependencies.

I will cover both topics in next articles.

Sample application you can find here ViewFactory.zip (83.71 kb)

Code for this article is also available on github as previous ones from Xamarin series.



Xamarin Master-Detail Page

clock April 24, 2016 03:41 by author n.podbielski

This article as previous ones (Frame With Padding, Frame Outline Problem, Inheritance from Implicit Styles) also will be about Xamarin.
This time we will inspect Master-Detail page control/mechanism. You can find official documentation for this control here.

Quick spoiler: I never used this in any production application. Why? I will explain. Whole article will be to explain why this is just not worth your time. In this and subsequent articles I will introduce much better solution.

Xamarin MasterDetailPage control

Ok lets get to work. For a test drive lets say we have to do an application that allows user to browse stuff on some online shop. Master-Detail page will be used to allow user switch to a different category of wares. According to documentation user have to introduce only 3 files (at least) to make this work. Since I am lazy I will not create whole menu but only Master view and 3 Detail views (we cannot waste time on creating nice UI just for test right? Smile)

First main application xaml file:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:masterDetail="clr-namespace:MasterDetail;assembly=MasterDetail"
             x:Class="MasterDetail.App">
  <Application.MainPage>
    <masterDetail:MasterPage />
  </Application.MainPage>
</Application>

This cannot be more straightforward so there is no need to explain. Lets focus on MasterPage view instead:

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:masterDetail="clr-namespace:MasterDetail;assembly=MasterDetail"
             x:Class="MasterDetail.MasterPage">
  <MasterDetailPage.Master>
    <ContentPage Title = "Test">
      <StackLayout>
        <Button Text="Detail1" />
        <Button Text="Detail2" />
        <Button Text="Detail3" />
      </StackLayout>
    </ContentPage>
  </MasterDetailPage.Master>
  <MasterDetailPage.Detail>
    <NavigationPage>
      <x:Arguments>
        <masterDetail:Detail1 />
      </x:Arguments>
    </NavigationPage>
  </MasterDetailPage.Detail>
</MasterDetailPage>

This file is a little more complicated but after few seconds it is clear that intention is to have 3 'menu' buttons that send you to different Detail pages.

Single Detail page could look like this:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MasterDetail.Detail1">
  <Label Text="Detail1" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

Again, nothing interesting just a label to see if correct Detail page is displayed.

Above application will start and display something similar to this:

 

Ok. I lied a little. Smile You need one more file to actually make navigation between Detail pages work. Ok lets handle this in MasterPage.xaml.cs code behind and create those details pages. For now two more files will be enough.

using System;
using Xamarin.Forms;

namespace MasterDetail
{
    public partial class MasterPage
    {
        public MasterPage()
        {
            InitializeComponent();
        }

        private void Button1_OnClicked(object sender, EventArgs e)
        {
            Detail = (new Detail1());
        }

        private void Button2_OnClicked(object sender, EventArgs e)
        {
            Detail = new NavigationPage(new Detail2());
        }

        private void Button3_OnClicked(object sender, EventArgs e)
        {
            Detail = new NavigationPage(new Detail3());
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MasterDetail.Detail3">
  <Label Text="Detail3" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MasterDetail.Detail2">
  <Label Text="Detail2" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

First: code behind that handles navigation. If you will read carefully you will notice some differences in handling detail pages. Two others are almost exactly the same as fist Detail page.

After running that solution you will see that there are really no difference between Detail1 and Detail2.

 

Why new NavigationPage() then? Because Xamarin documentation says:

The page type is wrapped in a NavigationPage instance in order to ensure that the icon referenced through the Icon property on the MasterPage is shown on the detail page in iOS.

Ok... But what if you do not write for iOS? They do not say. So you have to ensure iOS compatibility... you know just in case. Why you? Should not Xamarin take care of things like that?

Anyway, even after enclosing all of the detail pages inside a NavigationPage (even if just for having exactly the same view layout in all of them) it do not work quite well.

Why? Let us do quick experiment and press back button (if there is one on device) - it will cause application to go into background (or at least it does on Android). What is the cause of that? It works like that because there is change of NavigationPage with every Detail page and NavigationPage is object that handles... well navigation.

Luckily there is a rather easy fix for this too:

namespace MasterDetail
{
    public partial class MasterPage
    {
        public MasterPage()
        {
            InitializeComponent();
        }

        private void Button1_OnClicked(object sender, EventArgs e)
        {
            ChangeDetail(new Detail1());
        }

        private void Button2_OnClicked(object sender, EventArgs e)
        {
            ChangeDetail(new Detail2());
        }

        private void Button3_OnClicked(object sender, EventArgs e)
        {
            ChangeDetail(new Detail3());
        }

        private void ChangeDetail(Page page)
        {
            var navigationPage = Detail as NavigationPage;
            if (navigationPage != null)
            {
                navigationPage.PushAsync(page);
                return;
            }
            Detail = new NavigationPage(page);
        }
    }
}

Since there is a bit of logic involved a new method has been added - ChangeDetail. I think it is self explanatory: we just test if there is already NavigationPage and reuse that one.

This is again code that could be easily (and should be in my opinion) in Xamarin implementation of Detail property. But hey! There is Master-Detail mechanism right? If you unlucky to be unhappy with it - well you are unlucky. Xamarin Team certainly can't let you have virtual property Detail so you could do that a better way (they have rather unpleasant tendency to have everything internal/closed/sealed).

Let us continue main topic. Just for the sake of an example lets pretend that your manager, or marketing team, or anyone that is using your appm, thinks that application do not need that wide navigation menu. They think that 50 units will suffice and they ask if you can change it. You are starting maybe from setting it in StackLayout:

<StackLayout WidthRequest="50">
  <Button Text="Detail1" Clicked="Button1_OnClicked" />
  <Button Text="Detail2" Clicked="Button2_OnClicked" />
  <Button Text="Detail3" Clicked="Button3_OnClicked" />
</StackLayout>

But if does not work. Ok... Maybe this will work:

<ContentPage Title="Test" WidthRequest="50">
  <StackLayout WidthRequest="50">
    <Button Text="Detail1" Clicked="Button1_OnClicked" />
    <Button Text="Detail2" Clicked="Button2_OnClicked" />
    <Button Text="Detail3" Clicked="Button3_OnClicked" />
  </StackLayout>
</ContentPage>

No. Maybe MasterDetailPage.Master have property for this? Nope. Maybe MasterDetailPage? Nope. You can't do that. Xamarin developers did not think of that. You would have to forward the information that this change is impossible (or better easily done/would require one week of work Smile) for now.

After some time you maybe have another request, but with remark that this is absolutely necessary: menu have to go to the right edge.

You can check if MasterBehaviour property have something that can help you with that and according to documentation its enumeration type have following values:

  • Default – The pages are displayed using the platform default.
  • Popover – The detail page covers, or partially covers the master page.
  • Split – The master page is displayed on the left and the detail page is on the right.
  • SplitOnLandscape – A split screen is used when the device is in landscape orientation.
  • SplitOnPortrait – A split screen is used when the device is in portrait orientation.

As you see it does not anything helpful. Since there are only four other properties in this control you loose hope and explains to anyone requesting this change that it will need 2 weeks of works since you have to research new solution, implement and test it. At least.

Maybe I am pessimist but there are always changes and they in 90% about adding new features/code instead of removing so it is much more probable that you will have to change how Master and Detail mechanism work because of new requirement/device/theme etc.

Of course you can modify presentation by creating new renderer but it is really complex class and would only solve issues in one platform. No. This is not recommended solution. 

All those missing features and inability to configure anything is just only part of the problem. How many times you are writing application with Xaml files that uses only views without any view models? I personnally can't think of one. Even the smallest applications are written with few views and view models for them. Even models and database for small application are not that rare.

Lets think about above example. You have menu handlers in .xaml.cs file. I almost never use those and instead of them I use commands. Can you use them here? Not really, because you don't have access to Detail property in different object. You would have to create static property or method at least to allow yourself have access to property that is pretty much whole point of this control.
But static property can not be used in tests (at least easily) so better is to create special interface and have public access to its implementation somewhere. IoC container maybe? If you use this pattern you probably have IoC constructors in some classes, most probably in view models and those can't be created easily in view click handlers, like in above example, or in ListView.ItemSelected handler like Xamarin documentation suggests.

Best thing is to use commands and some interface in my opinion. This would be easiest thing to do to amend that discrepancy. But lets think of it from other angle.

I am big fan of separating classes in smaller parts for readability, easier maintenance, testability etc. The same thing can in my opinion can be said (to some extent) about xaml files. Can this be done in MasterPage.xaml file? For example you will decide to extract from there Master page and put it in Menu.xaml. Can you do that? Not easily because you can not move ButtonX_OnClicked handlers easily because they depend of MasterDetailPage.Detail property. Of course you can create interface the same as with view model problem, but again it shows that MasterDetailPage control creates more problems then it solves.

After reading about this control I decided not to use it because all of things covered above. In fact in my opinion this control is pretty much useless, But what to use instead?

ContentTemplate and ContentPresenter

First idea is to use newly added features of templating mechanism by ContentTemplate and ContentPresenter.

Let us add new button to MasterPage.xaml file:

<Button Text="Detail4" Clicked="Button4_OnClicked" />

To create ContentTemplate we have to add just one item to resources in our application, preferably in App.xaml:

<Application.Resources>
  <ResourceDictionary>
    <ControlTemplate x:Key="DetailTemplate">
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="250"></ColumnDefinition>
          <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackLayout BackgroundColor="Red">
          <Button Text="Detail1"></Button>
          <Button Text="Detail2"></Button>
          <Button Text="Detail3"></Button>
        </StackLayout>
        <ContentPresenter Grid.Column="1">
            
        </ContentPresenter>
      </Grid>
    </ControlTemplate>
  </ResourceDictionary>
</Application.Resources>

There is only 3 buttons just to show that it is different view. Red background is for the same thing. There is no handling of buttons because of the problems with MasterDetailPage control explained above. It is just a demo for templating mechanism.

Creating forth detail page called Detail4 like this:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MasterDetail.Detail4"
             ControlTemplate="{StaticResource DetailTemplate}">
  <Label Text="Detail4" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

is enough for now.

Last thing is to handle button click MasterPage.xaml.cs:

private void Button4_OnClicked(object sender, EventArgs e)
{
    App.Current.MainPage = new Detail4();
}

Yes this is also handled in xaml code behind file, but since this uses static App.Current property it can be easily moved to view model command property.

After running and trying out new button we will see something like this.

 

We have 250 width, red background. We can edit this view in every way possible for any page. We will do not have any problems with previous example change requests.

But there is other problem. What if we will have use state somehow in a way of coloring or disabling current page button? It is not that easy. Since it is a template and not separate control we can't have different BindingContext for menu and Detail page. The same view model for both sooner or later will cause some problems and it will not be most obvious one, using the same view model for all or maybe different ones but with the same values for menu?

More complex problems will be caused by complexity of menu. If you will have to i.e. 2-level menu and collapse, expand sub menus user will almost sure will see that every time after opening new detail page.

This mechanism is more usable for theming application, reusing some external library control with styles for every application etc.

If not templates then what?

Custom MasterDetail control

Yes. If you want job done well, do it your self.

First of all, requirements:

1. Control should have default view model.

2. Changing detail pages must be handled from view models.

3. Control should be created once.

4. Control should handle back button.

5. View should be allowed to override when neccessary.

 

Seems easy, right? Smile

Lets start with creating App.xamlfile and its code behind file:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomMasterDetail.App">
</Application>
namespace CustomMasterDetail
{
    public partial class App
    {
        public App()
        {
            InitializeComponent();
            MainPage = new MasterDetail();
        }
    }
}

Simple right? To make this correct we have to also create this MasterDetail class. But since view model is required, let us start there:

using System.ComponentModel;
using System.Runtime.CompilerServices;
 
namespace CustomMasterDetail.ViewModel
{
    public class MasterDetailViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
 
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

For now this can be any view model – it is just a minimal base implementation. We need to add Detail property:

private View _detail;
public View Detail
{
    get { return _detail; }
    set
    {
        _detail = value;
        OnPropertyChanged();
    }
}

If you wondering about OnPropertyChange call, yes it will be binded. It is not clearest implementation of View-ViewModel pattern but it is clear and simple and it will be enough for now.

Ok. Lets jump to view. We will start with simple xaml page:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomMasterDetail.MasterDetail">
</ContentPage>

There are two things missing:

  1. Menu
  2. Detail page presentation

To add them we need to create xaml definition for first and BindableProperty for second one. We will start with second one.

public readonly BindableProperty DetailProperty = BindableProperty.Create("Detail",typeof(ContentPage));
 
public ContentPage Detail
{
    get { return (ContentPage)GetValue(DetailProperty); }
    set { SetValue(DetailProperty, value); }
}

There is one thing that might be confusing. Detail property type is a ContentPage because of example simplicity. It could be also View because this is base type of any control that could be root of detail page layout (Grid, StackLayout etc.). Page would be also doable but it would require some magic to obtain root view from i.e. CarouselPage and still allow user to use its navigation features.

We will get back to this topic.

Menu will be the same as in previous examples.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="250" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <StackLayout Grid.Column="0">
        <Button Text="Detail1" />
        <Button Text="Detail2" />
        <Button Text="Detail3" />
    </StackLayout>
</Grid>

Grid control allows us to add menu and detail page and controls how they are connected in very simple but yet powerful way.

We need to connect Detail properties of control and view model and we can do that with simple binding:

public MasterDetail()
{
    InitializeComponent();
    SetBinding(DetailProperty, new Binding("Detail", BindingMode.OneWay));
}

We need to do this in a code behind and not in xaml because xaml operate in base class context and we need this in our class. Yes we could do this in other xaml file (in this case in App.xaml) but then we had to do this every single time we would use this control, which would really defeat whole purpose of creating separate control

Now we can define where Detail page will be in our layout and it will be second column of Grid. Of course this can any other place in Master page – top, right, bottom. You can even create multiple parts of master page that are permanently visible, in every detail page. Doing this way you can create i.e. extra properties in master view model and in detail view models that allows you hide, show this other parts, change displayed text, add buttons and etc. This is why it is better to do it this way instead of using Xamarin poor control.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="250" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <StackLayout Grid.Column="0">
        <Button Text="Detail1" />
        <Button Text="Detail2" />
        <Button Text="Detail3" />
    </StackLayout>
    <ContentView Grid.Column="1" x:Name="DetailContainer" />
</Grid>

Change of view model property. triggers change of View property. which is handled in BindableProperty definition via propertyChanged parameter:

public readonly BindableProperty DetailProperty = BindableProperty.Create("Detail",
    typeof(ContentPage), typeof(MasterDetailControl),
    propertyChanged: (bindable, value, newValue) =>
    {
        var masterPage = (MasterDetailControl)bindable;
        View content;
        var contentPage = (ContentPage)newValue;
        if (contentPage != null)
        {
            content = contentPage.Content;
            content.BindingContext = contentPage.BindingContext;
        }
        else content = null;
        masterPage.DetailContainer.Content = content;
        masterPage.OnPropertyChanged("SideContentVisible");
    });

Now it is much clearer why there is ContentPage type used for Detail properties in view and view model –  this type have Content property, which is set as Content of our newly added ContentView control named DetailContainer. It is important to mark why there is assignment of content BindingContext property - without it this value (in masterPage.DetailContainer.Content) would be resolved to parent value, which would be MasterDetailControl.BindingContext. We do not want that. Instead there is assigned directly detail view model to it, which is what is expected when you edit detail page xaml - it suppose to be this page view model.

Ok. As you can see we have easily configurable layout of control, Detail page easily accessible from ViewModel. However we do not have required support for INavigation interface right?

Let’s take care of it now. Easiest way will be to add this interface to view model:

public MasterDetailViewModel(INavigation navigation)
{
     _navigation = navigation;
}

private Stack _pages = new Stack();

public void InsertPageBefore(Page page, Page before)
{
    if (_pages.Contains(before))
    {
        var list = _pages.ToList();
        var indexOfBefore = list.IndexOf(before);
        list.Insert(indexOfBefore, page);
        _pages = new Stack(list);
    }
    else
    {
        _navigation.InsertPageBefore(page, before);
    }
}

public Task PopAsync()
{
    Page page = null;
    if (_pages.Count > 0)
    {
        page = _pages.Pop();
        _detail = page;
        OnPropertyChanged("Detail");
    }
    return page != null ? Task.FromResult(page) : _navigation.PopAsync();
}

public Task PopAsync(bool animated)
{
    Page page = null;
    if (_pages.Count > 0)
    {
        page = _pages.Pop();
        _detail = page;
        OnPropertyChanged("Detail");
    }
    return page != null ? Task.FromResult(page) : _navigation.PopAsync(animated);
}

public Task PopModalAsync()
{
    return _navigation.PopModalAsync();
}

public Task PopModalAsync(bool animated)
{
    return _navigation.PopModalAsync(animated);
}

public Task PopToRootAsync()
{
    var firstPage = _navigation.NavigationStack[0];
    if (firstPage is MasterDetail
        || firstPage.GetType() == typeof(MasterDetail))
    {
        _pages = new Stack(new[] { _pages.FirstOrDefault() });
        return Task.FromResult(firstPage);
    }
    return _navigation.PopToRootAsync();
}

public Task PopToRootAsync(bool animated)
{

    var firstPage = _navigation.NavigationStack[0];
    if (firstPage is MasterDetail
        || firstPage.GetType() == typeof(MasterDetail))
    {
        _pages = new Stack(new[] { _pages.FirstOrDefault() });
        return Task.FromResult(firstPage);
    }
    return _navigation.PopToRootAsync(animated);
}

public Task PushAsync(Page page)
{
    Detail = page;
    return Task.FromResult(page);
}

public Task PushAsync(Page page, bool animated)
{
    Detail = page;
    return Task.FromResult(page);
}

public Task PushModalAsync(Page page)
{
    return _navigation.PushModalAsync(page);
}

public Task PushModalAsync(Page page, bool animated)
{
    return _navigation.PushModalAsync(page, animated);
}

public void RemovePage(Page page)
{
    if (_pages.Contains(page))
    {
        var list = _pages.ToList();
        list.Remove(page);
        _pages = new Stack(list);
    }
    _navigation.RemovePage(page);
}

public IReadOnlyList ModalStack { get { return _navigation.ModalStack; } }

public IReadOnlyList NavigationStack
{
    get
    {
        if (_pages.Count == 0)
        {
            return _navigation.NavigationStack;
        }
        var implPages = _navigation.NavigationStack;
        MasterDetail master = null;
        var beforeMaster = implPages.TakeWhile(d =>
        {
            master = d as MasterDetail;
            return d is MasterDetail || d.GetType() == typeof(MasterDetail);
        }).ToList();
        beforeMaster.AddRange(_pages);
        beforeMaster.AddRange(implPages.Where(d => !beforeMaster.Contains(d)
            && d != master));
        return new ReadOnlyCollection(_navigation.NavigationStack.ToList());
    }
}

It may look a little complicated but most important are only 2 methods, PushAsync and PopAsync for navigation inside an application. Modal windows functionality is just redirected to Xamarin implementation of interface. ModalStack and NavigationStack properties may be usable sometimes. First just unifies Xamarin stack and MasterPage stack (from _pages field) into one. Rest of interface is not really helpfull in most of applications, but it is implemented as ax example even if would be possible to implement only PopAsync and PushAsync methods or even creating simpler interface only for navigation inside MasterPage.

With that kind of implementation of INavigation interface we can use it inside of OnBackButtonPressed override in MasterPage:

protected override bool OnBackButtonPressed()
{
    var viewModel = BindingContext as MasterDetailViewModel;
    if (viewModel != null)
    {
        var navigation = (INavigation)viewModel;
        navigation.PopAsync();
        return true;
    }
    return base.OnBackButtonPressed();
}

Above code fulfils our requirements. MasterDetail.xaml is easy to change and it is created only once. MasterDetailViewModel is specific view model for control and its INavigation implementation makes detail page navigation easily available from outside of control. The same interface allows handling of backbutton in control.

Next thing to do: it would be nice to have MasterDetail control in reusable portable library.

MasterDetailControl in PCL library

Placing our new control in separate PCL (Portable Class Library), allow to reuse it in multiple applications. It is very useful if you have multiple applications with similar themes. Then it is possible to place whole theme in single PCL.

Lets start with creating PCL project i.e. named CustomMasterDetailControl. We need to add xaml file and view model class to this project. Most of that code will be copied from previous example.

First, xaml file MasterDetailControl.

<?xml version="1.0" encoding="utf-8"?>

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                x:Class="CustomMasterDetailControl.MasterDetailControl">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="250" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <StackLayout Grid.Column="0" x:Name="SideContentContainer" />
        <ContentView Grid.Column="1" x:Name="DetailContainer" />
    </Grid>
</ContentPage>

There is one change from previous version. Instead of having menu in StackLayout control we just assigning name to this control so now it is available in code behind.

public partial class MasterDetailControl
{
    public static readonly BindableProperty SideContentProperty = BindableProperty.Create("SideContent",
        typeof(View), typeof(MasterDetailControl), null, propertyChanged: (bindable, value, newValue) =>
        {
            var control = (MasterDetailControl)bindable;
            control.SideContentContainer.Children.Clear();
            control.SideContentContainer.Children.Add(control.SideContent);
        });

    public readonly BindableProperty DetailProperty = BindableProperty.Create("Detail",
    typeof(ContentPage), typeof(MasterDetailControl),
    propertyChanged: (bindable, value, newValue) =>
    {
        var masterPage = (MasterDetailControl)bindable;
        masterPage.DetailContainer.Content = newValue != null ?
            ((ContentPage)newValue).Content : null;
    });

    public MasterDetailControl()
    {
        InitializeComponent();
        SetBinding(DetailProperty, new Binding("Detail", BindingMode.OneWay));
    }

    public ContentPage Detail
    {
        get { return (ContentPage)GetValue(DetailProperty); }
        set { SetValue(DetailProperty, value); }
    }

    public View SideContent
    {
        get { return (View)GetValue(SideContentProperty); }
        set { SetValue(SideContentProperty, value); }
    }

    public static Page Create<TView, TViewModel>() where TView : MasterDetailControl, new()
        where TViewModel : MasterDetailControlViewModel, new()
    {
        var masterDetail = new TView();
        var navigationPage = new NavigationPage(masterDetail);
        var viewModel = new TViewModel();
        viewModel.SetNavigation(navigationPage.Navigation);
        masterDetail.BindingContext = viewModel;
        return navigationPage;
    }

    protected override bool OnBackButtonPressed()
    {
        var viewModel = BindingContext as MasterDetailControlViewModel;
        if (viewModel != null)
        {
            var navigation = (INavigation)viewModel;
            navigation.PopAsync();
            return true;
        }
        return base.OnBackButtonPressed();
    }
}

With Bindable property defined like this we can override side content of MasterDetailControl in our every application like this:

<MasterDetailControl.SideContent>
    <StackLayout>
        <Button Text="Detail1" Command="{Binding ToDetail1}" />
        <Button Text="Detail2" Command="{Binding ToDetail2}" />
        <Button Text="Detail3" Command="{Binding ToDetail3}" />
    </StackLayout>
</MasterDetailControl.SideContent>

Very easy and intuitive.

There is also new method that should be used to create instance of our control and override view model type for it:

public static Page Create<TView, TViewModel>() where TView : MasterDetailControl, new()
    where TViewModel : MasterDetailControlViewModel, new()
{
    var masterDetail = new TView();
    var navigationPage = new NavigationPage(masterDetail);
    var viewModel = new TViewModel();
    viewModel.SetNavigation(navigationPage.Navigation);
    masterDetail.BindingContext = viewModel;
    return navigationPage;
}

This method contains logic that was previously in App.xaml.cs file:

public App()
{
    InitializeComponent();
    var masterDetail = new MasterDetail();
    var navigationPage = new NavigationPage(masterDetail);
    MainPage = navigationPage;
    masterDetail.BindingContext = new MasterDetailViewModel(navigationPage.Navigation);
}

However there is no point in forcing this code in every application. Instead we can use new method in following way:

public App()
{
    InitializeComponent();
    MainPage = MasterDetailControl.Create<MasterDetail, MasterDetailViewModel>();
}

Best way to set MainPage of application in my opinion would be to set it in xaml file of App class, but this would force as to i.e. rewrite our control so it would derive from NavigationPage instead and then add the same Bindable properties to this new type to propagate those values to our actual control. I do not think that getting rid one line in code justifies that kind of complexity.

Of course if MasterDetailViewModel class do not have parameterless constructor (because of IoC i.e.) we can create new method that takes instance of view model type and change previous overload a little:

public static Page Create<TView, TViewModel>() where TView : MasterDetailControl, new()
    where TViewModel : MasterDetailControlViewModel, new()
{
    return Create<TView, TViewModel>(new TViewModel());
}

public static Page Create<TView, TViewModel>(TViewModel viewModel) where TView : MasterDetailControl, new()    
    where TViewModel : MasterDetailControlViewModel
{
    var masterDetail = new TView();
    var navigationPage = new NavigationPage(masterDetail);
    viewModel.SetNavigation(navigationPage.Navigation);
    masterDetail.BindingContext = viewModel;
    return navigationPage;
}

Now lets focus on base class for new control view model: MasterDetailControlViewModel. It is almost the same as in previous example, but it do not contain any logic that handles side menu functionality.

public class MasterDetailControlViewModel : INotifyPropertyChanged, INavigation
{
    private Page _detail;
    private INavigation _navigation;

    private Stack<Page> _pages = new Stack<Page>();

    public event PropertyChangedEventHandler PropertyChanged;

    public Page Detail
    {
        get { return _detail; }
        set
        {
            if (_detail != value)
            {
                _pages.Push(Detail);
                _detail = value;
                OnPropertyChanged();
            }
        }
    }

    public IReadOnlyList<Page> ModalStack { get { return _navigation.ModalStack; } }

    public IReadOnlyList<Page> NavigationStack
    {
        get
        {
            if (_pages.Count == 0)
            {
                return _navigation.NavigationStack;
            }
            var implPages = _navigation.NavigationStack;
            MasterDetailControl master = null;
            var beforeMaster = implPages.TakeWhile(d =>
            {
                master = d as MasterDetailControl;
                return master != null || d.GetType() == typeof(MasterDetailControl);
            }).ToList();
            beforeMaster.AddRange(_pages);
            beforeMaster.AddRange(implPages.Where(d => !beforeMaster.Contains(d)
                && d != master));
            return new ReadOnlyCollection<Page>(_navigation.NavigationStack.ToList());
        }
    }

    public void InsertPageBefore(Page page, Page before)
    {
        if (_pages.Contains(before))
        {
            var list = _pages.ToList();
            var indexOfBefore = list.IndexOf(before);
            list.Insert(indexOfBefore, page);
            _pages = new Stack<Page>(list);
        }
        else
        {
            _navigation.InsertPageBefore(page, before);
        }
    }

    public Task<Page> PopAsync()
    {
        Page page = null;
        if (_pages.Count > 0)
        {
            page = _pages.Pop();
            _detail = page;
            OnPropertyChanged("Detail");
        }
        return page != null ? Task.FromResult(page) : _navigation.PopAsync();
    }

    public Task<Page> PopAsync(bool animated)
    {
        Page page = null;
        if (_pages.Count > 0)
        {
            page = _pages.Pop();
            _detail = page;
            OnPropertyChanged("Detail");
        }
        return page != null ? Task.FromResult(page) : _navigation.PopAsync(animated);
    }

    public Task<Page> PopModalAsync()
    {
        return _navigation.PopModalAsync();
    }

    public Task<Page> PopModalAsync(bool animated)
    {
        return _navigation.PopModalAsync(animated);
    }

    public Task PopToRootAsync()
    {
        var firstPage = _navigation.NavigationStack[0];
        if (firstPage is MasterDetailControl
            || firstPage.GetType() == typeof(MasterDetailControl))
        {
            _pages = new Stack<Page>(new[] { _pages.FirstOrDefault() });
            return Task.FromResult(firstPage);
        }
        return _navigation.PopToRootAsync();
    }

    public Task PopToRootAsync(bool animated)
    {
        var firstPage = _navigation.NavigationStack[0];
        if (firstPage is MasterDetailControl
            || firstPage.GetType() == typeof(MasterDetailControl))
        {
            _pages = new Stack<Page>(new[] { _pages.FirstOrDefault() });
            return Task.FromResult(firstPage);
        }
        return _navigation.PopToRootAsync(animated);
    }

    public Task PushAsync(Page page)
    {
        Detail = page;
        return Task.FromResult(page);
    }

    public Task PushAsync(Page page, bool animated)
    {
        Detail = page;
        return Task.FromResult(page);
    }

    public Task PushModalAsync(Page page)
    {
        return _navigation.PushModalAsync(page);
    }

    public Task PushModalAsync(Page page, bool animated)
    {
        return _navigation.PushModalAsync(page, animated);
    }

    public void RemovePage(Page page)
    {
        if (_pages.Contains(page))
        {
            var list = _pages.ToList();
            list.Remove(page);
            _pages = new Stack<Page>(list);
        }
        _navigation.RemovePage(page);
    }

    public void SetNavigation(INavigation navigation)
    {
        _navigation = navigation;
    }

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Anything that will involve siide menu will be in application specific code view model. Application will contains from the same detail views.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomMasterDetail2.DetailX">
  <Label Text="DetailX" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

App.xaml file is also the same and most of its code behind was shown above.

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomMasterDetail2.App">
</Application>
using CustomMasterDetailControl;

namespace CustomMasterDetail2
{
    public partial class App
    {
        public App()
        {
            InitializeComponent();
            MainPage = MasterDetailControl.Create<MasterDetail, MasterDetailViewModel>();
        }
    }
}

MasterDetail.xaml file is application specific implementation of control and contains menu (the same as in previous example).

<?xml version="1.0" encoding="utf-8" ?>
<masterDetail:MasterDetailControl 
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:masterDetail="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
    x:Class="CustomMasterDetail2.MasterDetail">
    <masterDetail:MasterDetailControl.SideContent>
        <StackLayout>
            <Button Text="Detail1" Command="{Binding ToDetail1}" />
            <Button Text="Detail2" Command="{Binding ToDetail2}" />
            <Button Text="Detail3" Command="{Binding ToDetail3}" />
        </StackLayout>
    </masterDetail:MasterDetailControl.SideContent>
</masterDetail:MasterDetailControl>

Menu logic is of course contained in view model, MasterDetailViewModel class.

public class MasterDetailViewModel : MasterDetailControlViewModel
{
    private ICommand _toDetail1;
    private ICommand _toDetail2;
    private ICommand _toDetail3;

    public ICommand ToDetail1
    {
        get
        {
            return _toDetail1 ?? (_toDetail1 = new Command(OnToDetail1));
        }
    }

    public ICommand ToDetail2
    {
        get
        {
            return _toDetail2 ?? (_toDetail2 = new Command(OnToDetail2));
        }
    }

    public ICommand ToDetail3
    {
        get
        {
            return _toDetail3 ?? (_toDetail3 = new Command(OnToDetail3));
        }
    }

    private void OnToDetail1()
    {
        Detail = new Detail1();
    }

    private void OnToDetail2()
    {
        Detail = new Detail2();
    }

    private void OnToDetail3()
    {
        Detail = new Detail3();
    }
}

After running this application effect will be the same as in previous one.

 

Best thing about this solution is great possibilities of configuration. In MasterDetailControl.xaml you can change anything you want: layout, widths, heights of elements, adds new bars on top or bottom, etc.

For example if we would want to hide menu on some detail pages, we can add new property to our control:

public bool SideContentVisible
{
    get { return Detail.SideContentVisible; }
}

Obviously for this to work there is need for above property SideContentVisible in detail page. Since our details are just ContentPage class instances we need to create new base class for details. Best way is to put it in PCL library along to our MasterDetailControl class.

public class DetailPage : ContentPage
{
    public DetailPage()
    {
        SideContentVisible = true;
    }

    public bool SideContentVisible { get; set; }
}

Obviously we need to change base classes of all details for this work. It is sometimes unnecessary or not desired, so let's change property in master detail control instead.

public bool IsMenuVisible
{
    get
    {
        var detailPage = Detail as DetailPage;
        if (detailPage != null)
        {
            return detailPage.SideContentVisible;
        }
        return true;
    }
}

This will handle ContentPage details to - menu visibility will just default to true. We can now create new detail called i.e. NoMenuDetail.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<masterDetail:DetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                         xmlns:masterDetail="clr-namespace:CustomMasterDetailControl;assembly=CustomMasterDetailControl"
                         x:Class="CustomMasterDetail2.NoMenuDetail"
                         SideContentVisible="False">
  <Label Text="No menu detail page" VerticalOptions="Center" HorizontalOptions="Center" />
</masterDetail:DetailPage>

We need only to add new menu item to application MasterDetail.xaml and handle this item command in view model.

<Button Text="NoMenuDetail" Command="{Binding ToNoMenuDetail}" />
private ICommand _toNoMenuDetail;

public ICommand ToNoMenuDetail
{
    get
    {
        return _toNoMenuDetail ?? (_toNoMenuDetail = new Command(OnToNoMenuDetail));
    }
}

private void OnToNoMenuDetail()
{
    Detail = new NoMenuDetail();
}

We need, of course, to create appropriate binding for this in MasterDetailControl.xaml and notify about property change, everytime Detail property changes.

<?xml version="1.0" encoding="utf-8"?>

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomMasterDetailControl.MasterDetailControl"
             x:Name="Parent">
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <StackLayout Grid.Column="0" x:Name="SideContentContainer"
                 WidthRequest="250"
                 IsVisible="{Binding SideContentVisible, Source={x:Reference Name=Parent}}" />
    <ContentView Grid.Column="1" x:Name="DetailContainer" />
  </Grid>
</ContentPage>

Binding is done by referencing control by its xaml name "Parent", which allows us to use it for binding source. It is impossible any other way in Xamaring without custom IMarkupExtension implementation (but I strongly encourage you to do that Smile). Another thing, that is worth to explain, is Auto width of side content Grid column. Without that change this column would take space even if its content would be invisible. Width of 250 is moved to WidthRequest property of StackLayout that serve as a container for menu.

Notification about SideContentVisible property change should be done every time detail changes and it involves only one line in DetailProperty declaration.

public readonly BindableProperty DetailProperty = BindableProperty.Create("Detail",
    typeof(ContentPage), typeof(MasterDetailControl),
    propertyChanged: (bindable, value, newValue) =>
    {
        var masterPage = (MasterDetailControl)bindable;
        masterPage.DetailContainer.Content = newValue != null ?
            ((ContentPage)newValue).Content : null;
        masterPage.OnPropertyChanged("SideContentVisible");
    });

After running changed code we will see on mobile device screen something like this:

 

After clicking on new menu item menu will disapper:

 

Summary

Above examples can serve as a base to create more specific controls thanks to great flexibility of this solution. It is defined by developer and it is tottally open in contrast to Xamarin native solution with it internal functionality, not accesible to end user of Xamarin. Since navigation really happens in view model it is much more viable for bigger applications that in most cases do not have parameterless constructors for view models and other classes. Base classes for control and its view model handles basic functionality, which can be extened very easily, so there is no need to do it every time in every single application. Control is created only once, which helps conserve memory. This would be impossible if every single page had the same menu. Oh, and it handles back button well Smile.

Sample applications with code examples used in this article you can find here: XamarinSamples.zip (94.48 kb)

Also there is available public github repository with code for this article and previous ones from Xamarin series.

Some features might still be missing or few things might be handled better. For example navigation from view model could be done by creating view models instead of views. This is better pattern and it is much simpler since navigation requires creating only one instance of view model instead of view and view model (at least in final application logic code). This would need some mechanism for finding out proper view for view model and/or registration mechanism for those pairs. Also it would be much easier to have the same navigation for detail pages and simple, whole screen content pages. For this detail pages can identified by base class DetailPage. This would create nice and simple navigation for every page via just view models regardless of specifics of a layout of views (which should not be connected to application logic anyway).

I will cover those topics in next article.

 



Xamarin Style based on implicit Style

clock April 22, 2016 19:17 by author n.podbielski

Next article about bugs in Xamarin will touch topic of Styles. Styles for all of controls not only Frame (and if you wondering why Frame you should check first two articles about Xamarin here and here).
First of all if you are using Styles in Xamarin you probably know how to define implicit styles. If not here is a sample:

<Application.Resources>
  <ResourceDictionary>
    <Style TargetType="Label">
      <Setter Property="FontSize" Value="45" />
    </Style>
  </ResourceDictionary>
</Application.Resources>

Almost the same as in WPF. If you will, or already did, use those kind of styles extensively you probably encountered problem with inheritance from them. How to do it? First consider this xaml:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="StylesInheritance.App">
  <Application.Resources>
    <ResourceDictionary>
      <Style TargetType="Label">
        <Setter Property="FontSize" Value="45" />
      </Style>
    </ResourceDictionary>
  </Application.Resources>
  <Application.MainPage>
    <ContentPage>
      <Grid>
        <Grid.Resources>
          <ResourceDictionary>
            <Style TargetType="Label">
              <Setter Property="BackgroundColor" Value="Red"></Setter>
            </Style>
          </ResourceDictionary>
        </Grid.Resources>
        <Label Text="Label Text" />
      </Grid>
    </ContentPage>
  </Application.MainPage>
</Application>

You have global implicit style for Label and want, locally for Grid, add red background too. According to this Xamarin documentation it should be possible right? Style have BaseResourceKey property, which won't be helpful since implicit styles do not have keys (actually they do but we will get back to this), but there is also property BasedOn. If you have Resharper you can even taste how this should work with Intellisense:

Should work, but it do not. Ok. Resharper inserts what it looks like a correct Xaml:

<Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
  <Setter Property="BackgroundColor" Value="Red"></Setter>
</Style>

 But after application starts we have (un)welcoming error:

 

Why this resource is not found? It is there, right? Notice strange key value, we will get back to that.

Maybe you will (or already did tried) to use Key property of StaticResourceExtension?

<Style TargetType="Label" BasedOn="{StaticResource Key={x:Type Label}}">
  <Setter Property="BackgroundColor" Value="Red"></Setter>
</Style>

You will see another error:

 

That was something to be expected really since Key property is a string.

If you are so distrustful as me, maybe you tried to actually inspect Application resources to check if they are really there:

 

Implicit style is there oh right. Why Framework cannot find something that put in there itself? If you are perceptive you probably noticed that Keys is collection of strings and implicit styles actually do have keys, which are FullName of target types. We will have to do figure out how to set appropriate key for this type of styles. The easiest way is:

<Style TargetType="Label" BasedOn="{StaticResource Xamarin.Forms.Label}">
  <Setter Property="BackgroundColor" Value="Red"></Setter>
</Style>

<Style TargetType="Label" BasedOn="{StaticResource Key=Xamarin.Forms.Label}">
  <Setter Property="BackgroundColor" Value="Red"></Setter>
</Style>

The problem with first solution is that Resharper marks it as invalid (yeah this is really weak problem, but I like to my code to be clean that way) and second is not even checked for validity - you can put there anything - so it is even worse since you have only runtime errors. Of cource you can also assign proper key to implicit styles and make them explicit, and then assign this key to all controls, and then assign this key to child styles, and... well... this is to much work Wink.

On the side, I really do not get why Xamarin Team decided to make Resources keys a string and not objects like in WPF. If this would be the case, second Style declaration would work just fine.

{StaticResource Key={x:Type Label}}

In my opinion this is first bug/improvement they should make.

For fixing this issue I decided to write my own StaticResourceExtension, that will correctly calculate resources keys. Unfortunately as almost everything that could be useful to override in Xamarin is sealed (see Binding i.e.; not sealed in WPF). Because of that we have to do this this way:

[ContentProperty("KeyOrType")]
public class StaticResourceExtExtension : IMarkupExtension
{
    private readonly StaticResourceExtension _xamarinStaticExtension;

    public StaticResourceExtExtension()
    {
        _xamarinStaticExtension = new StaticResourceExtension();
    }

    public object KeyOrType { get; set; }

    public object ProvideValue(IServiceProvider serviceProvider)
    {
        var type = KeyOrType as Type;
        if (type != null)
        {
            _xamarinStaticExtension.Key = type.FullName;
        }
        else
        {
            var s = KeyOrType as string;
            if (s != null)
            {
                _xamarinStaticExtension.Key = s;
            }
        }
        return _xamarinStaticExtension.ProvideValue(serviceProvider);
    }
}

This will work only in newer versions of Xamarin. For example in 1.3.3.6323 this class is internal (which is interesting how it is available in Xaml). In earlier versions you have resolve to reflection or write your own mechanism for obtaining correct resources (it is not really that complicated).

With this you declare your style like this:

<Style TargetType="Label" BasedOn="{stylesInheritance:StaticResourceExt {x:Type Label}}">
  <Setter Property="BackgroundColor" Value="Red"></Setter>
</Style>

Which will still throw and error Undecided, which is strange to me and it is second bug involving styles inheritance.

 

It is the same error as in the first try with Xamarin StaticResourceExtension. If you will debug this code you can check for KeyOrType property value:

This is the point when I just stopped amazed what I found. Laughing

Really, I expected a bug, but not like this one. If you will look closely on first screen with error, you will notice that the same thing happens in Xamarin extension (and why I think that using Xamarin is like run through minefield). Apparently Xaml parser do not expect here another extension and it threats everything as plain string instead of evaluating it and then putting it in StaticResourceExtension. However this is only one thing. Why there is no closing bracket '}'? Maybe first problem originates from second one and parser threats unclosed brackets as just string and not correctly as Xaml declaration. If we add explicitly KeyOrType property to declaration it will be resolved by parser just right.

<Style TargetType="Label" BasedOn="{stylesInheritance:StaticResourceExt KeyOrType={x:Type Label}}">
  <Setter Property="BackgroundColor" Value="Red"></Setter>
</Style>

But we did not got so far without doing it (almost) perfect! Good thing we can change how our extension behaves, in contrast to Xamarin one. We have only to resolve type from its xaml abbreviation. Luckily IServiceProvider have access for type just for that: IXamlTypeResolver. With method of this type:

Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider = null);

we can easily obain correct type.

public object ProvideValue(IServiceProvider serviceProvider)
{
    var type = KeyOrType as Type;
    if (type != null)
    {
        _xamarinStaticExtension.Key = type.FullName;
    }
    else
    {
        var s = KeyOrType as string;
        if (s != null)
        {
            const string xType = "{x:Type ";
            if (s.StartsWith(xType))
            {
                var typeName = s.Replace(xType, "");
                var xamlTypeResolver = (IXamlTypeResolver)serviceProvider.GetService(typeof(IXamlTypeResolver));
                _xamarinStaticExtension.Key = xamlTypeResolver.Resolve(typeName, serviceProvider).FullName;
            }
            else
            {
                _xamarinStaticExtension.Key = s;
            }
        }
    }
    return _xamarinStaticExtension.ProvideValue(serviceProvider);
}

And it will work. As we wanted we will see big font label on red background.

 

Of course instead of removing "{x:Type " part of string it is possible to do this:

public object ProvideValue(IServiceProvider serviceProvider)
{
    var type = KeyOrType as Type;
    if (type != null)
    {
        _xamarinStaticExtension.Key = type.FullName;
    }
    else
    {
        var s = KeyOrType as string;
        if (s != null)
        {
            const string bracket = "{";
            if (s.StartsWith(bracket))
            {
                var xamlTypeResolver = (IXamlTypeResolver)serviceProvider.GetService(typeof(IXamlTypeResolver));
                var extensionName = s.Replace(bracket, "").Split(' ')[0];
                var extension = (TypeExtension)Activator.CreateInstance(xamlTypeResolver.Resolve(extensionName, serviceProvider));
                extension.TypeName = s.Split(' ')[1];
                var typeName = extension.ProvideValue(serviceProvider).FullName;
                _xamarinStaticExtension.Key = typeName;
            }
            else
            {
                _xamarinStaticExtension.Key = s;
            }
        }
    }
    return _xamarinStaticExtension.ProvideValue(serviceProvider);
}

But I think there is no point in that. This code is much less clear and also not 100% percent bulletproof. I think it is worth to do only if you planning to add your own extension for type resolving, because styles added to resources either have Type.FullName key or just some arbitrary name as key. Previous solution is then sufficient. Below is sample application.

 StylesInheritance.zip (54.13 kb)

Also there is available public github repository with code for this article and other ones from Xamarin series.



Xamarin Frame and disappearing Outline

clock April 22, 2016 09:00 by author n.podbielski

This is another article in mini series of Xamarin bugs and workarounds for them Smile. Previous one you can find here.

This one is again about Frame control. I promise that another one will be about something else Cool.

Issue can be observed when you bind BackgroundColor property of Frame control and something will trigger change of view model source property binded to background color.

But since one image is more than thousand words - here is gif with this bug.

 

Frame is quite big, but if you look near corners of it, you will see, that there are round when background is green and when background change to Red, they disappear. Outline disappear too. It is slight white line around green field (it is even less visible), but I assure you that it is there. Smile

Ok here is a code for this example in xaml App file:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FrameBug.App">
  <Application.MainPage>
    <ContentPage>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="*"></RowDefinition>
          <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <StackLayout Padding="10">
          <Frame VerticalOptions="Center" OutlineColor="White" 
                 BackgroundColor="{Binding LineColor}">
            <Label Text="Label" FontSize="60" />
          </Frame>
        </StackLayout>
        <Button Text="Change color" Grid.Row="1" Command="{Binding ChangeColor}"></Button>
      </Grid>
    </ContentPage>
  </Application.MainPage>
</Application>

One noticable thing done in code behind for this xaml file is adding BindingContext instance (App.xaml.cs file):

namespace FrameBug
{
    public partial class App
    {
        public App()
        {
            InitializeComponent();
            BindingContext = new AppViewModel();
        }
    }
}

Ok. One missing piece is AppViewModel class:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Xamarin.Forms;

namespace FrameBug
{
    public class AppViewModel : INotifyPropertyChanged
    {
        private ICommand _changeColor;

        public event PropertyChangedEventHandler PropertyChanged;

        public ICommand ChangeColor => _changeColor ?? (_changeColor = new Command(OnChangeColor));

        public Color LineColor { get; set; } = Color.Green;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private void OnChangeColor()
        {
            LineColor = Color.Red;
            OnPropertyChanged("LineColor");
        }
    }
}

As you may notice it is C# code from VS2015. It will not work in prior versions, but there is not really point in doing test Xamarin apps in earlier versions since Xamarin recently was released for free even in VS2015 community edition.

With this simple application added to Xamarin template solution we can reproduce bug as in above gif. But how to fix it? And why it occurs? It took some digging and Resharper help with decompiling FrameRenderer to find out why. Yes, this class that renders Frame control as plain bitmap in Android environment is source of the problem. This class (since there is no public source code I will not include disassembled source code) have private UpdateBackground method which creates custom class based on Android Drawable class. It in its bowels it renders Background with solid color from BackgroundColor property of Frame control and Outline as a line (or rather rounded rectangle) from OutlineColor property of Frame. Those methods suppose to work either on initialization or BackgroundColor, OutlineColor properties change according to code of mentioned class. All good, right? When I created very similar class, attached it to custom renderer of Frame both operations was performed correctly during debugging session. But still frame was drawn incorrectly. It took some experimentation with height and width of rectangles in bitmap and it struck me that nothing happens even with 1x1 px size, because background is rerendered in some other place. Where? Since no more code in renderer was touching drawing it had to be in base class - VisualElementRenderer<>. If you disassemble it too, you will see that it have SetBackgroundColor and it was my first suspect. This method is executed on property change of control. Which one you ask? Smile BackgroundColor property. I did not dig any further since it is virtual method. Quick test proved my suspect guilty. Adding following override method to custom renderer fixed this problem.

public override void SetBackgroundColor(Color color)
{

}

Since code in FrameRenderer and its base class was executing correctly it probably was executing in wrong order. Probably it was missed by Xamarin Team after fixing this bug and closing this one. Or maybe this method as virtual was added after fix and tests and testers missed it? Nevertheless, writing new custom renderer based on Xamarin one fix this issue:

[assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))]
namespace FrameBug.Droid
{
    public class FrameRenderer : Xamarin.Forms.Platform.Android.FrameRenderer
    {
        public override void SetBackgroundColor(Color color)
        {
            //base.SetBackgroundColor(color);
        }
    }
}

Commented line can be used to trigger the buggy behavior if anyone is curious enough Smile.

This is another one of mine unpleasant adventures with Xamarin framework. I hope this can be helpful and spare you some time. You can find sample application below.

FrameBug.zip (52.56 kb)

Also there is available public github repository with code for this article and other ones from Xamarin series.



Xamarin Frame and Style with Padding

clock April 22, 2016 01:10 by author n.podbielski

If you are a bit advanced with Xamarin you should already now that there is possibility of styling your controls almost like in WPF.
Almost, because there is a few strange bugs involving this. For example there is a problem with styling a Padding property in Frame. Consider following Xaml of Xamarin application (I tested it in Android):

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:styles="clr-namespace:Styles;assembly=Styles"
             x:Class="Styles.App">
  <Application.Resources>
    <ResourceDictionary>
      <Style TargetType="Frame" x:Key="Style">
        <Setter Property="Padding" Value="0" />
      </Style>
    </ResourceDictionary>
  </Application.Resources>
  <Application.MainPage>
    <ContentPage>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="100" />
            <RowDefinition Height="100" />
            <RowDefinition Height="100" />
          <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Frame VerticalOptions="Center"
               Grid.Row="0"
               Padding="0">
          <Label Text="100 height" FontSize="60" />
        </Frame>
        <Frame VerticalOptions="Center" Style="{StaticResource Style}"
               Grid.Row="1"
               Padding="0">
          <Label Text="100 height" FontSize="60" />
        </Frame>
        <Frame VerticalOptions="Center" Style="{StaticResource Style}"
               Grid.Row="2">
          <Label Text="100 height" FontSize="60" />
        </Frame>
      </Grid>
    </ContentPage>
  </Application.MainPage>
</Application>

It almost the same as default (created by template) shared application - but instead of App.cs we have more advanced Xaml file.

What not suspecting (or better: excepting a normal behavior) user would except all Frames to have the same view because properties will have the same values. Should have the same values, but they are not. This code will produce following layout:

 

Last Frame do not have explicit setting for Padding in its declaration and this property is resolved to default value and its contents just do not fit in available space. Why? There is a bug for that.

But according to comments Xamarin Team is not exactly willing to fix it.

Fortunately there is a quick workaround for that. The easiest thing to do is to just add this method to new class named i.e. FixedFrame:

public class ExtendedFrame : Frame
{
    protected override void OnPropertyChanged(string propertyName = null)
    {
        // ReSharper disable once ExplicitCallerInfoArgument
        base.OnPropertyChanged(propertyName);
        if (propertyName == StyleProperty.PropertyName)
        {
            if (Style.Setters.Any(s => s.Property == PaddingProperty))
            {
                Padding = (Thickness)Style.Setters.First(s => s.Property == PaddingProperty).Value;
            }
        }
    }
}

Using this class instead of original Frame from Xamarin framework will ensure proper Padding value after applying Style to FixedFrame control. Consider changed Android application from above, with added new FixedFrame control at the end. Only property set is Style and theer is no explicit value for Padding in control declaration:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:styles="clr-namespace:Styles;assembly=Styles"
             x:Class="Styles.App">
  <Application.Resources>
    <ResourceDictionary>
      <Style TargetType="Frame" x:Key="Style">
        <Setter Property="Padding" Value="0" />
      </Style>
    </ResourceDictionary>
  </Application.Resources>
  <Application.MainPage>
    <ContentPage>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="100" />
            <RowDefinition Height="100" />
            <RowDefinition Height="100" />
          <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Frame VerticalOptions="Center"
               Grid.Row="0"
               Padding="0">
          <Label Text="100 height" FontSize="60" />
        </Frame>
        <Frame VerticalOptions="Center" Style="{StaticResource Style}"
               Grid.Row="1"
               Padding="0">
          <Label Text="100 height" FontSize="60" />
        </Frame>
        <Frame VerticalOptions="Center" Style="{StaticResource Style}"
               Grid.Row="2">
          <Label Text="100 height" FontSize="60" />
        </Frame>
        <styles:FrameExt VerticalOptions="Center" Style="{StaticResource Style}"
               Grid.Row="3">
          <Label Text="100 height" FontSize="60" />
        </styles:FrameExt>
      </Grid>
    </ContentPage>
  </Application.MainPage>
</Application>

As a result we will have following window layout:

 

As you see last row with FixedFrame control have proper Padding property value. Smile
Simple and effective. Below sample application.

Styles.zip (324.08 kb)

Also there is available public github repository with code for this article and other ones from Xamarin series.



Safe cast string to enum

clock February 25, 2014 18:49 by author n.podbielski

In on of my projects I had make an interface between database and web service in C# code.

One of problem I had to face was need to cast strings to enumerable types, because of simple fact that database have no idea what is an 'enum'. Yes simplest mapping between an enumeration and database type is integer. It is simplest but in my idea not best. For example I really do not remember (or do not WANT to remember) what is the meaning of 4 integer value in case of package shipment status.

We can have values like this:

0 - RequestReceived
1 - Accepted
2 - Assembling
3 - Sended
4 - CustomerReceived
5 - Completed

Let's assume that is valid flow of package delivery flow. For someone that is working on system that handles monitoring of that kind of mechanism, this could be not an issue, because this flow is easy to recall. Yes. But as company grows, software grows. And most likely more enumeration types will be created.

So to have best of to worlds, in my opinion this is best to have enumeration in strings and with possibility to cast strings like '0' and 'RequestReceived' to RequestReceived enum value.

Nice feature is to make casting also case insensitive. But this is not necessary.

Aside from interfacing with database there are other use case that come to mind:

1. User interfaces input

2. Type serialization to JSON and from JSON

3. XML serialization

4. Import from various data sources like CSV

Ok. That is for introduction. Let's go to the coding.

First we have to retrieve values of enum type:

var values = Enum.GetValues(typeof(TEnum));

This is simple. Static method of Enum special class returns all possible values of an enum. With that knowledge we can just use foreach loop to iterate through collection:

public static EnumTest GetEnumValue(string val)
{
    var values = Enum.GetValues(typeof(EnumTest));
    foreach (EnumTest value in values)
    {
        if (val.Equals(value.ToString()))
        {
            return value;
        }
    }
    return 0;
}

There is a few problems with this method. For first: we can use it with only one predefined type of enum. Sadly this is impossible to create generic enum-only method in C#. But we can do pretty close. Second problem is that we don't have too have default value of enum type with integer equivalent of 0. 0 can not be in an enum at all!
 For first issue we can add generic type argument with constraints of interfaces implemented by enum types and with struct special constraint.
 For second issue we can use default C# keyword. Our 'better' method will be declared as following:

public static TEnum GetEnumValue(string val)
    where TEnum : struct, IComparable, IFormattable, IConvertible
{
    var values = Enum.GetValues(typeof(TEnum));
    foreach (TEnum value in values)
    {
        if (val.Equals(value.ToString()))
        {
            return value;
        }
    }
    return default(TEnum);
}

Of course there are can be other types that can work with this method but are in fact not an enumerable types, but this is best solution available in C# (that I know of). Default statement in case where string value is not found in method will return first defined value of an enum.

Next step will be add possibility of integers values in strings. For that we have to cast enum values to type int. We cannot do that with simple casting operation in C#, because it is not possible with generic type we defined in our improved method. But we can use IConvertible interface and its ToInt32 method. It requires format provider for casting though. I used CultureInfo.CurrentCulture property which was OK in my application, but this could be a problem in others. It depends where it will be used. Changed method will look like this:

 

public static TEnum GetEnumValue2(string val)
    where TEnum : struct, IComparable, IFormattable, IConvertible
{
    var values = Enum.GetValues(typeof(TEnum));
    foreach (TEnum value in values)
    {
        if (val.Equals(value.ToString())
            || val == (value.ToInt32(CultureInfo.CurrentCulture)).ToString())
        {
            return value;
        }
    }
    return default(TEnum);
}

This mostly work ok, but this might be a problem when it is used like this:

package.Status = GetEnumValue<PackageStatus>(newStatusString);

Why? Because when newStatusString value is not proper value for and enum, status property will reset to default status value. It might be a problem. Solution might be exception throwing when value is invalid. This would be good for UI. I decided to use custom default value:

package.Status = GetEnumValue(newStatusString, package.Status);

This way status will not change if value in string is inalid and old value will be assigned.

Finally I added case insensitivity for string comparison. There are plenty of possibilities to do that in .NET so this is something that should be considered in regards of application which will be using that code. For example we can do something like this:

public static TEnum GetEnumValue2(string val,TEnum current)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
    var values = Enum.GetValues(typeof(TEnum));
    foreach (TEnum value in values)
    {
        if (val.Equals(value.ToString(), StringComparison.OrdinalIgnoreCase)
            || val == (value.ToInt32(CultureInfo.CurrentCulture)).ToString())
        {
            return value;
        }
    }
    return current;
}

Nice have feature is to defined this method as extension method for string. This way we can call it after writing name of the variable with our string value.

package.Status = newStatusString.GetEnumValue(package.Status);

I prefer to do this that way, because it is more expressive to my coding style. While writing solution for some kind of a problem I think: I want here this value but after mapping it in the following way. With using method GetEnumValue as a plain method not extension, it is in my opinion greater burden for someone who read code (which is mostly me and I always want to make my life easier :) ). But this is subject of another article.

Anyway this can be achieved just by adding this keyword and placing method in separate class.

public static class Extension
{
    public static TEnum GetEnumValue( this string val, TEnum current)
where TEnum : struct, IComparable, IFormattable, IConvertible
    {
        var values = Enum.GetValues(typeof(TEnum));
        foreach (TEnum value in values)
        {
            if (val.Equals(value.ToString(), StringComparison.OrdinalIgnoreCase)
                || val == (value.ToInt32(CultureInfo.CurrentCulture)).ToString())
            {
                return value;
            }
        }
        return current;
    }
}

This is very simple solution for this particular problem. There are more thing that can be changed/improved. You can download code sample and play with it yourself :)

Enjoy!

 Program.cs (3.55 kb)