InternetException

About coding and whatnot.

Xamarin with TinyIoC

clock December 10, 2016 10:48 by author n.podbielski

Introduction


This article is builds on topics and solutions introduces in ViewFactory for Xamarin application and Xamarin Master-Detail Page articles. It shows method for easier navigation and use of services via IoC in Xamarin application.
Knowledge from previous examples is not necessary, but makes this article bit easier to understand.

For IoC container it will use TinyIoC, but not vanilla version from author GitHub repository (or from Nuget). I will use my personal fork, because this version can be used in PCL projects, which allows TinyIoC to be placed inside shared project, which makes it much easier.

[Update]Version 1.3.0 od TinyIoC suppose to have PCL support, but it does not work. [/UPDATE]

Otherwise, with original version, which is incompatible with PCL version of .NET, we would be force to place the same TinyIoC code in every platform project. It does complicate things unnecessary. With PCL enabled version this is no longer a problem.

Idea is to use IoC container to:

  1. Create seamless navigation between views
  2. Resolve application services in view models

 

Easy navigation

It is important to note, that new navigation mechanism, should work for usual Xamarin views that are descendants from Xamarin Page class and also for pages deriving from DetailPage class. Detail views are the ones that have to be placed inside master page like it was explained in Master-Detail article. With navigation mechanism like that, we can easily navigate to another from view model (which should holds that kind of logic anyway) to another page using its view model, completely oblivious to detail of view implementation.

Navigation to view model type by resolving that type from IoC container, allows to inject this model dependencies in very easy and elegant way via constructor. You need show to the user GPS location? You just need to add new constructor parameter with IGSPService and use obtained reference.

How to do it? First we need to create Xamarin application with shared project - IoCSample. In this article I will use Android platform. Rest of platform projects are not necessary. After creating projects we need to add few references to Android project: ViewFactory, ViewFactory.Android and CustomMasterDetailControl (all are available in XamarinSamples, where this article code will be added also). Those projects are neccessary to implement better navigation between views. CustomMasterDetailControl assembly contains MasterDetailControl, which will allow us to create detail views and put them inside defined master control. Detail views along with ordinary Xamarin views will allow to show how navigation is independent from views definitions. ViewFactory projects will be used internally by navigation for views creation. After that we can add TinyIoC file with IoC container definition. This class do not need any initialization. Use of static value TinyIoCContainer.Current is enough for our needs.

Now we can change default application. Here is content of App.xaml. App.xaml.cs and MainActivity.cs files, if we do things without IoC.

<?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="IoCSample.App">
</Application>
public partial class App
{
    public App ()
    {
        InitializeComponent();
        MainPage = new MainPageView { BindingContext = new MainPageViewModel() };
    }
}
[Activity(Label = "IoCSample", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        global::Xamarin.Forms.Forms.Init(this, bundle);
        LoadApplication(new IoCSample.App());
    }
}

We are creating two instances: view and view model to create main page for application. Goal is to use ViewFactory to create page from view model type. To do that we need to first register ViewFactory service in IoC, but because ViewFactory is defined in Android platform project (because few Reflection features are not that easily accessible from PCL and it is much easier from full .NET in platform project; however this is possible in PCL but exceeds scope of this article), we also need to register this service in platform class - MainActivity.

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    RegisterServices(TinyIoCContainer.Current);
    global::Xamarin.Forms.Forms.Init(this, bundle);
    LoadApplication(new IoCSample.App());
}

private void RegisterServices(TinyIoCContainer container)
{
    container.Register<IViewFactory, VFactory>();
}

IViewFactory is new interface for ViewFactory class, which will make use of it more convenient with IoC.

public interface IViewFactory
{
    UIPage CreateView<TViewModel>() where TViewModel : BaseViewModel;

    UIPage CreateView<TViewModel, TView>() where TViewModel : BaseViewModel
        where TView : UIPage;

    UIPage CreateView<TViewModel, TView>(TViewModel viewModel) where TViewModel : BaseViewModel
        where TView : UIPage;

    UIPage CreateView(Type viewModelType);
    void Init(Assembly appAssembly);
}

Then we can initialize MainPage of application, with ViewFactory.

public IViewFactory viewFactory { get; set; }

public App()
{
    var container = TinyIoCContainer.Current;
    container.BuildUp(this);
    viewFactory.Init(Assembly.GetExecutingAssembly());
    InitializeComponent();
    MainPage = viewFactory.CreateView<MainPageViewModel>();
}

After starting application we will see MainPage, which proves that ViewFactory, IoC combo work.

Ok, but still it is just creation of new value for MainPage property of application. How to implement easier navigation? If you are not planning single page application, we need Xamarin INavigation instance. Easiest way to obtain one is to create NavigationPage instance as value for MainPage instead.

MainPage = new NavigationPage(viewFactory.CreateView<MainPageViewModel>());

Now let's create another page to be able to test if new navigation works.

<?xml version="1.0" encoding="UTF-8"?>
<customMasterDetailControl:UIPage 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="IoCSample.PageView">
  <Label Text="{Binding Label}" HorizontalOptions="Center" VerticalOptions="Center"/>
</customMasterDetailControl:UIPage>

Next step is to create navigation between view models. We can create static class NavigationHelper for this.

public class NavigationHelper
{
    private static readonly INavigation _navigation;
    private static readonly IViewFactory _viewFactory;
    private static TinyIoCContainer _container;

    static NavigationHelper()
    {
        var container = TinyIoCContainer.Current;
        _container = container;
        _viewFactory = container.Resolve<IViewFactory>();
        _navigation = container.Resolve<INavigation>();
    }

    public static void NavigateTo<TViewModel>() where TViewModel : BaseViewModel
    {
        _navigation.PushAsync(_viewFactory.CreateView<TViewModel>());
    }

    public static void NavigateTo<TViewModel>(Action<TViewModel> init) where TViewModel : BaseViewModel
    {
        var viewModel = _container.Resolve<TViewModel>();
init(viewModel); _navigation.PushAsync(_viewFactory.CreateView(viewModel)); } }

It uses new CreateView method inside ViewFactory class.

public UIPage CreateView<TViewModel>(TViewModel viewModel)
{
    var viewModelType = viewModel.GetType();
    if (Views.ContainsKey(viewModelType))
    {
        var viewData = Views[viewModelType];
        return CreateView(viewModel, viewData.Creator);
    }
    return null;
}

Above method allows us to create page with given view model. But it would made things problematic if view model need to be initialized somehow before navigation to its page. For example product details new instance or identificator of a product. We can create new button inside MainPage which will cause navigation to new PageView with initialization action to show how this works.

New view model looks like below.

public class PageViewModel : BaseViewModel
{
    public void SetLabelText(string value)
    {
        Label = value;
    }

    public string Label { get; set; }
}

Initialization method and property that is binded to view label. Navigation to this page is implemented with new NavigationHelper class called from MainPageView button.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <Label Grid.Row="0" Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
    <Button Grid.Row="1" Text="To Page" Command="{Binding ToPage}" />
</Grid>
public ICommand ToPage
{
    get
    {
        return _toPage ?? (_toPage = new Command(() =>
                {
                    NavigationHelper.NavigateTo<PageViewModel>(
                        vm => vm.SetLabelText("Value from MainPageViewModel"));
                }));
    }
}

After build and run, application correctly navigates from MainPageView to PageView.

 

The same command but without initialization of view model is less complicated and looks like this.

public ICommand ToPage
{
    get
    {
        return _toPage ?? (_toPage = new Command(NavigationHelper.NavigateTo<PageViewModel>));
    }
}

There is also possibility of creating i.e. IViewModelInit interface with Init() method, but it creates another problem. How to define parameters in this method? If this will be single object type value, it forces cast to correct type to set necessary data in view model. If we do not want casting we need to create generic BaseViewModel<> class with generic method for initialization. But still it forces us to put types in two places (type definition and initialization method), which complicates code that usually changes very often and still exists problem with number of parameters (though I never saw such method with more than two parameters). This is why i decided to leave it like this.

Nevertheless, we can simplify this further by creating method for navigating inside base view model class. Ideally it would be to put inside BaseViewModel but it is referenced assembly without knowledge of NavigationHelper class. Because of that we need to create new NavigationViewModel type with those method and then change application view models base types.

public class NavigationBaseViewModel : BaseViewModel
{
    public static void NavigateTo<TViewModel>() where TViewModel : BaseViewModel
    {
        NavigationHelper.NavigateTo<TViewModel>();
    }

    public static void NavigateTo<TViewModel>(Action<TViewModel> init) where TViewModel : BaseViewModel
    {
        NavigationHelper.NavigateTo(init);
    }
}

After changing MainPageViewModel base class to type above we can rewrite ToPage command once again.

public ICommand ToPage
{
    get
    {
        return _toPage ?? (_toPage = new Command(() =>
        {
            NavigateTo<PageViewModel>(vm => vm.SetLabelText("Value from MainPageViewModel"));
        }));
    }
}

In one line we can now order our application to:

  1. Create view model instance
  2. Initialize view model instance with appropriate data from previous view
  3. Create new view
  4. Set view model in new view
  5. Show new view to the user

 

Pretty elegant solution comparing to what is required in Xamarin by default.

public ICommand ToPageXamarin
{
    get
    {
        return _toPage ?? (_toPage = new Command(() =>
        {
            var newView = new PageView();
            var newViewModel = new PageViewModel();
            newViewModel.SetLabelText("Value from MainPageViewModel");
            newView.BindingContext = newViewModel;
            var navigation = App.Current.MainPage.Navigation;
            navigation.PushAsync(newView);
        }));
    }
}

Above code gets even more comlicated if PageViewModel would have some dependecies with dependecies etc.

 

How about navigation to Detail pages?

Next step is to implement navigation to detail pages too in the same way - by single call to NavigateTo<> method. This requires us to change NavigationHelper class. Problem with static class is that we can't enforce in any way necessity of pointing out which Master page should be used. Of course you can have one single file for all of yours application, but I highly doubt it. In Most of the time, they will differ a little. Because of that, even class MasterPageControl as in previous article might not be enough since it i.e. lacks ability to put menu on the left side of application (but can be easily achieved by modification of MasterPageControl.xaml file). Of course it is possible to create static property, let's say called MasterPageViewModelType, which would point out, which master view should be used for detail pages, but this is more error prone. I prefer to make code as clear to use as possible and then throw errors in run-time. Most of the time I am end user of my own code and I do not want to think how I should implement some mechanism to 'get things done' Smile. It should be easy and obvious as much as possible. Because of that better idea is to do service for navigation as abstract base class, with abstract property, with type of master page view model.

So we need base implementation of NavigationService. Good idea is to create generic class.

public class NavigationService<TMasterViewModel> : INavigationService<TMasterViewModel>
        where TMasterViewModel : MasterDetailControlViewModel
{
}

Most of the code is copied from NavigationHelper, but to implement detail views support we need add few new things.

public TMasterViewModel MasterViewModel
{
    get
    {
        var page = _navigation.NavigationStack.LastOrDefault();
        return page?.BindingContext as TMasterViewModel;
    }
}

Above property returns instance of master view model as type defined in class definition. Instance is not null only if there is already master page on top of a stack. Why? Because Xamarin INavigation do not allow the same page to be twice in the views stack (which makes sense) and this is why we need to create new master page every time detail page is added after ordinary, fullscreen page. Think of this as:

Master(Detail1) -> Full screen page -> Master(Detail2)

If you want to push new detail page on stack like above you can reuse last master page. But if you want to push new detail page on top, after 'full screen page' is on top, you cannot reuse previous one because it is already in other position. Therefore new instance has to be created.

With this knowledge we can implement new NavigateTo<> methods.

public void NavigateTo<TViewModel>() where TViewModel : BaseViewModel
{
    PushPage<TViewModel>(_viewFactory.CreateView<TViewModel>());
}

public void NavigateTo<TViewModel>(Action<TViewModel> init) where TViewModel : BaseViewModel
{
    var viewModel = _container.Resolve<TViewModel>();
    init(viewModel);
    PushPage<TViewModel>(_viewFactory.CreateView(viewModel));
}

public void PushPage<TViewModel>(Page page) where TViewModel : BaseViewModel
{
    if (!_viewFactory.IsDetailView<TViewModel>())
    {
        _navigation.PushAsync(page);
    }
    else
    {
        var masterViewModel = MasterViewModel;
        UIPage masterPage = null;
        if (masterViewModel == null)
        {
            masterPage = _viewFactory.CreateView<TMasterViewModel>();
            masterViewModel = (TMasterViewModel)masterPage.BindingContext;
        }
        masterViewModel.Detail = page;
        if (MasterViewModel == null)
        {
            _navigation.PushAsync(masterPage);
        }
    }
}

New PushPage method takes care of previous call to INavigation.PushAsync for ordinary (full screen) pages.

It uses new IsDetailView method of IViewFactory interface to found if page is detail view.

public bool IsDetailView(Type viewModelType)
{
    return Views[viewModelType].IsDetail;
}

public bool IsDetailView<TViewModel>() where TViewModel : BaseViewModel
{
    return IsDetailView(typeof(TViewModel));
}

ViewFactory already contains information if view is detail view or not. We just needed new method to extract this information from service.

If above method returns true for some view model it means that it has to be handled differently and cannot be directly pushed into INavigation stack. This different logic is handled by else clause in INavigationService.PushPage method. If there is no master page on top - it is created (as there was explained above) along with appropriate view by ViewFactory. After that new detail page is set in master and finally master page is pushed into navigation stack of Xamarin (if is not there yet). That explained, here is whole class will look like.

public class NavigationService<TMasterViewModel> : INavigationService<TMasterViewModel>
    where TMasterViewModel : MasterDetailControlViewModel
{
    private readonly TinyIoCContainer _container;

    private readonly INavigation _navigation;

    private readonly ViewSwitcher.IViewFactory _viewFactory;

    public NavigationService()
    {
        var container = TinyIoCContainer.Current;
        _container = container;
        _viewFactory = container.Resolve<ViewSwitcher.IViewFactory>();
        _navigation = container.Resolve<INavigation>();
    }

    public TMasterViewModel MasterViewModel
    {
        get
        {
            var firstOrDefault = _navigation.NavigationStack.FirstOrDefault();
            return firstOrDefault?.BindingContext as TMasterViewModel;
        }
    }

    public void NavigateTo<TViewModel>() where TViewModel : BaseViewModel
    {
        PushPage<TViewModel>(_viewFactory.CreateView<TViewModel>());
    }

    public void NavigateTo<TViewModel>(Action<TViewModel> init) where TViewModel : BaseViewModel
    {
        var viewModel = _container.Resolve<TViewModel>();
        init(viewModel);
        PushPage<TViewModel>(_viewFactory.CreateView(viewModel));
    }

    public void PushPage<TViewModel>(Page page) where TViewModel : BaseViewModel
    {
        if (!_viewFactory.IsDetailView<TViewModel>())
        {
            _navigation.PushAsync(page);
        }
        else
        {
            var masterViewModel = MasterViewModel;
            UIPage masterPage = null;
            if (masterViewModel == null)
            {
                masterPage = _viewFactory.CreateView<TMasterViewModel>();
                masterViewModel = (TMasterViewModel)masterPage.BindingContext;
            }
            masterViewModel.Detail = page;
            if (MasterViewModel == null)
            {
                _navigation.PushAsync(masterPage);
            }
        }
    }
}

Now we can finally put it to use. For example new button added to PageView in similar way like in MainPageView, will navigate to new DetailView.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Label Grid.Row="0" Text="{Binding Label}" HorizontalOptions="Center"
            VerticalOptions="Center"/>
    <Button Grid.Row="1" Text="To detail"  Command="{Binding ToDetailPage}" />
</Grid>

With view model like below.

public class PageViewModel : NavigationBaseViewModel
{
    private Command _toDetailPage;

    public void SetLabelText(string value)
    {
        Label = value;
    }

    public string Label { get; set; }

    public ICommand ToDetailPage
    {
        get
        {
            return _toDetailPage ?? (_toDetailPage = new Command(OnToDetailPage));
        }
    }

    private void OnToDetailPage()
    {
        NavigateTo<DetailViewModel>();
    }
}

But we need to define master page first - MasterDetailControl.

<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="IoCSample.Views.MasterDetailView">
    <masterDetail:MasterDetailControl.SideContent>
        <StackLayout>
            <Button Text="To detail page" Command="{Binding ToDetail}" />
        </StackLayout>
    </masterDetail:MasterDetailControl.SideContent>
</masterDetail:MasterDetailControl>

View model for above view looks like this.

public class MasterDetailViewModel : MasterDetailControlViewModel
{
    private ICommand _toDetai;
        
    public ICommand ToDetail
    {
        get { return _toDetai ?? (_toDetai = new Command(OnToDetail)); }
    }
        
    private void OnToDetail()
    {
        NavigationHelper.NavigateTo<Detail1ViewModel>();
    }
}

Now we need just to register new service in container, in App.xaml.cs file and we can try it out.

public void RegisterServices(TinyIoCContainer container)
{
    container.Register<INavigationService, NavigationService<MasterDetailViewModel>>();
}

After running this code we can see that, this works fine and should give result similar to image below.

 

Now, when we have Navigation implemented, we can jump to second topic.

ViewModels dependency injection.

Views are supposed to have no constructor dependencies. Models are usually just data or data containers, which data logic (add order for customer etc.). The only thing UI should have is application logic in view models. Most of the time they will obtain new data or show existing data to the user. But sometimes there is a need for some specific logic i.e. get GPS location, connect with Bluetooth device, generate pdf, show modal dialog etc. All those functions are more general and it is good idea to implement them as services that can be shared between different views and applications. Sharing can be implement by IoC container and Dependency Injection (via constructors) in view models.

What we need to do in our project to achieve that? Two things:

  1. ViewFactory should create view models from IoC container not Activator class.
  2. Register services during application initialization.

 

With those two we can add parameters to constructors with services interfaces.

Let's do first point first. It is quite easy and the only problem is that we have to create virtual method in BaseViewFactory class and overwrite it in new type defined in the same assembly as TinyIoC.

private UIPage CreateView(Type viewModelType, Func<UIPage> creator)
{
    var viewModel = CreateViewModelInstance(viewModelType);
    return CreateView(viewModel, creator);
}

protected virtual object CreateViewModelInstance(Type viewModelType)
{
    var viewModel = Activator.CreateInstance(viewModelType);
    return viewModel;
}

Above methods are part of changed BaseViewFactory. Logic is the same - create instance of type via Activator. Now, new type in IoCSample project.

public class IoCViewFactory : ViewFactory.ViewFactory.ViewFactory
{
    private readonly TinyIoCContainer _container;

    public IoCViewFactory(TinyIoCContainer container)
    {
        _container = container;
    }

    protected override object CreateViewModelInstance(Type viewModelType)
    {
        return _container.Resolve(viewModelType);
    }
}

As you can see we just had to overwrite virtual method to use IoC container instead of Activator class. This is all we had to do! Smile

Now we need to create and register some service to use it inside view models. Let's imagine that we have some mechanism to store cache data in database or in file. We can change and/or read it from any view model. For case of simplicity following class, interface is enough for our sample.

public class DataCacheService : IDataCacheService
{
    public Dictionary<string, object> DataCache { get; } = new Dictionary<string, object>();
}
public interface IDataCacheService
{
    Dictionary<string, object> DataCache { get; }
}

Really simple mechanism to save some information during runtime. We have to register this service in container. We can do this inside App.xaml.cs file.

public void RegisterServices(TinyIoCContainer container)
{
    container.Register<INavigationService, NavigationService<MasterDetailViewModel>>();
    container.Register<IDataCacheService, DataCacheService>().AsSingleton();
}

We can now share cached data by accessing service. For example we can save data in one view model - DetailViewModel and read it in another one - Detail1ViewModel. Saving is done by simple Entry control binded to view model property. Every time user change value of Entry, data is saved. Then after navigation to another view it will show saved data in its label. Below is code of mentioned view models.

public class DetailViewModel : BaseViewModel
{
    private readonly IDataCacheService _dataCacheService;
    private string _text;

    public DetailViewModel(IDataCacheService dataCacheService)
    {
        _dataCacheService = dataCacheService;
        if (_dataCacheService.DataCache.ContainsKey(CacheKey))
        {
            _text = (string)_dataCacheService.DataCache[CacheKey];
        }
    }

    public const string CacheKey = "CacheKey";

    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            _dataCacheService.DataCache[CacheKey] = value;
        }
    }
}
public class Detail1ViewModel : BaseViewModel
{
    public Detail1ViewModel(IDataCacheService dataCacheService)
    {
        if (dataCacheService.DataCache.ContainsKey(DetailViewModel.CacheKey))
        {
            Text = (string)dataCacheService.DataCache[DetailViewModel.CacheKey];
        }
    }

    public string Text { get; private set; }
}

Really simple example. Appropriate views for view models are even simpler and there is no point listings their code.

After running new application we can test if this actually works.

 

As you can see value entered in one view is accessible in second one. Dependency injection in view models works fine with automatic navigation to views by view model types, without consideration of specifics of view definition. Smile

Cleaned and refactored code (everything in one project) you can download from here: IoCFinal.zip (77.98 kb) or from github (with other Xamarin articles in the series).

 



Faster than Reflection: Delegates. Part 3.

clock September 2, 2016 14: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.

Code with new features and with bug fixes is available on GitHub and as Nuget package.

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 and as Nuget package.



Faster than Reflection: Delegates. Part 2.

clock August 16, 2016 13: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.

Last article in series you can find here.

Code with new features and with bug fixes is available on GitHub and as Nuget package.

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 the first thing we need is a way to indicate which one we need to call inside a delegate. Since constructors can differ by parameters types, we can do this in a similar way as with indexers - with 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 case is less complex we will discuss this first.

What we need to start? Since every type have at least one constructor, even if it is not defined explicitly, we do not need to add any code to our TestClass (from previous article). But, as before with other members, we have 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);
}

Logic behind above code is explained in details in previous article for other types of members. Quick explanation: it looks for public, then private and protected and last internal constructors.

Now we can implement a method, that will create delegate for default constructor. 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 method from previous article. First, constructor is obtained from type and then after null check it 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 in this case is our new instance.

How about case when we do not have access to type this way? We can write extension method for Type type, 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 in exactly the same way. In case you are wondering why there is no casting of return value to object, it is because source type is always a class type - structures cannot have parameterless constructors. You can easily test it by getting list of constructors of i.e. int type - no constructors returned by reflection.

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

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

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

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 source type) and parameter with list of types representing collection of constructor parameters.

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

Problem with above 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 much more universal.

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

Returned 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. 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 represented 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 on code, you can notice, that TestClass type parameter is passed twice: on its own and as return type of constructor delegate. It is not necessary and we can remove first one by obtaining source type with defined constructor from passed delegate type. It can be very easily done by below method.

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 above Constructor 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 new method to rewrite DefaultContructor method.

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

This should return delegate without parameters that returns instance, so Func<TSource> is passed as delegate type. But how about a case when we do not know source type and we want a delegate for constructor with parameters? We have to change Constructor method so it returns a delegate with return type of object. Because of that, we cannot 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 is almost the same as previous one, but it do returns an object instead of source type instance. If type to construct is value type 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 methods can have parameters that are also unknown or unavailable. 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, except 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 many parameters there are probably more important 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 the 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 converted to correct type of parameter at the same index. Collections of processed parameters is then used as a collection of arguments for constructor. Created instance is then converted to object if is of value type. This will look much clearer as a 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 via 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 used for testing all of delegates. Both are explained in the previous article in series. You can also look for a code for this article (and previous one) on github for more information.

All variables with names starting with 't' will have value of newly created instance. Constructors called via delegates c1, c2, c3 and c4 have different visibility (public, internal, protected and private) and it 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 this 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, 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 constructors 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 properties covered in the first article, it is time for methods, which are also one of the most used type of members. With experience gained by 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 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 type of method), 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 at all (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 not 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 uses 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), for void and not void methods.

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 we have to write a method for obtaining static method MethodInfo object, just like for 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 as previous members types. 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 a 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 StaticMethod methods would be similar to following lambda statement.

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, in the same way as a constructor called by objects in this article and other members in the previous one, it requires expressions to make it work.

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 properties setters. We can check if return type of method is void and omit casting to object and finally, cast delegate to return type from 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 a 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, lambda return value would be also converted to object.

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 then creates delegates that have single parameter no matter of number of parameters of target static method. They differs only by return type of created delegate (void or object). Next three works the same way, but for non-public methods. Last three tests all StaticMethod overloads, but for method that returns value type instead of reference type. Second part of above test just calls created delegates to make sure they works. Below image shows values returned by those calls.

 

Returned values are what they supposed to be, according to definitions of static methods in TestClass.

The last thing to do about static methods is to 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 prove again 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 only slower by few percent. Calls by array of object are obviously slower because, of all the casting and indexing; in above example it takes 2.5 times longer, but it should be less for more complicated method than just single return statement. Last line shows that reflection is much more slower, as expected (about 18 times).

The last thing to do is to add check 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 (similarly to properties). Instance methods are like static methods that takes first parameter with target instance, which give meaning to 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 can create delegate that could look like following static extension method.

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

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

Ok, let us implements overloads of InstanceMethod methods. First, will be the one with all types known (source, 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>

This method takes two parameters (instance, on which method should be called and target method parameter) and returns string. Rest of code is very similar to Constructor method. We take type parameters from TDelegate, first one is used as source type and rest to search for correct overload of target 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 (this) of extension method. Thing is, with instance methods we have the same problem like with constructors: we cannot create overload that takes unspecified number of type parameters and returns 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, 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 first parameter of delegate (either source instance, object or any other compatible type) is equal source parameter it works exactly as previous overload. If not, it performs delegate creation via expression, very similar to respective Constructor overload. List of parameters types returned from TDelegate is used to create ExpressionsParameter collection for Expression.Call. The same collection (with source parameter as object) is used as parameters set for Expression.Lambda. If statement casts returned value to object only if it is structure and if target 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);

There are two versions depending if we call it with delegate type with correct instance type or with just an object.

Now, we can discuss third overload that takes only objects (in two versions: for void and non-void methods) exactly the same way 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 overload is almost the same as similar one for static methods. The only thing that differs is one more parameter with instance 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, call target method, cast returned value if needed. 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 works and check performance of this solution. As before, with other members, we can do it for all 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 of 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;

The 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 and returned variables have expected values. Similar code, that was used to test performance of delegates to static methods, can be adjusted to test performance of instance ones.

_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 should be very much like this:

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

As you can see, delegates for instance methods (exactly like with other members) are just a little slower than direct call to method. 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 just need to cover events and special type of methods: generic methods. Both static and instance methods can be generic and along with events, they will be covered in next article.

Code for article can be found on github and as Nuget package.



Faster than Reflection: Delegates. Part 1.

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

This article is first part of the series of three. Next ones you can find here and here.

Code for all three articles, with new features and bug fixes is available on GitHub and as Nuget package.

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, the first solution involves Reflection. But the thing is: Reflection is slow. Of course, it is sufficient if you need to use Reflection rarely and it is not the main code of the 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?

The 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 an 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 than reflection.

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

 

 The 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 the 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 these members. Frankly, not all of those delegates make 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.

The 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 be to create ordinary event and invoke it from a singleton instance. The good thing is that it is pretty easy to create a delegate for a static event with just a small change for instance event.

 

 

Static Properties

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

I think the 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 a new project. It will be called Delegates - console application for easy tests.

The first thing to do is to create class for tests. We can name 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";
}

The second thing is to create a class for delegates creation - DelegatesFactory. How we can retrieve static property? The best way is to retrieve it is via Type instance that represents information about our source type. We can make it an extension method for Type type. This way, it will be more convenient. We need to know about the property we want, so parameter with property name and type parameter with its return type is also a 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 the second method (extension one) is more general, we will implement it first. To create a delegate, we need PropertyInfo for the requested property. Yes, we need reflection for that. The thing is, that many of the delegates require reflection, but it is just one time, for creation of delegate. After that, we can use this delegate with just a small overhead, since the program will have to execute two nested methods instead of one.

The most important part in retrieving property via reflection is that we have access to PropertyInfo.GetMethod that way and GetMethod is MethodInfo type, which will have CreateDelegate member. The 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 the 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.

The 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 a little more complicated (and in my opinion, more confusing) and requires both flags Public and NonPublic. An 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>));
}

The above code is pretty easy to understand. If property is not public it tries to find it as private or protected. If this is 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<string>("StaticPublicProperty");
        var sp2 = Type.StaticPropertyGet<string>("StaticInternalProperty");
        var sp3 = Type.StaticPropertyGet<string>("StaticProtectedProperty");
        var sp4 = Type.StaticPropertyGet<string>("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 the 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 an ordinary way. The second one uses delegates. After running the changed code, we can find out that the difference is not that big, really.

Static Public property: 404
Static Public property retriever: 472

Retrieving 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 a simple string. With more complex properties that are calculating its return value first, the difference would be smaller. Just for the 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 the changed code, the 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 a complete look at things, let us do one more test. If you ever used Expression type and its methods, 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 the one with reflection. It creates a lambda function that could look like this for TestClass.StaticPublicProperty.

() => TestClass.StaticPublicProperty

Now, we can test the 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, the expression is much, much more slower than reflection. I do not investigate this further, but I think that it has something to do with compiling expression to delegate. Unfortunately, it is not possible to create delegates for all members just by using reflection, so it is a 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 the 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 is supposed to be a method that does not take parameters and returns value of type object. How to implement this new StaticPropertyGet? We need code for retrieving PropertyInfo for needed static property. The best thing is to create a 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;
}

The 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 a 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). The 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 the following code.

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

The above lines executed will write value of 'StaticPublicProperty', which is the 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. The 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 use only reflection: one extension method and one with type parameter as source type.

For overload that does 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 - expressions 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 fail 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 in 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 the 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, the 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 has 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 return 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 instances. So instead of Func<TProperty>, we 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 first we need a 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 the 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 tests 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. The following four lines are after calls to set delegates and have new 'test' values. Good. Everything works!

Improvements

The main problem with methods like the above for retrieving and setting instance properties is that those require type to be known at compile time, which is sometimes impossible since some types are private. But if you do not have type, you cannot create delegate that has this type instance as parameter. The only solution for this is to create a method that takes object and hopes that it is the correct instance of correct type Smile. The 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 the 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.

The 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 the first case we know type of property and in the 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 the appropriate delegate with Expression class. The 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();

The 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 look 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, the 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 the 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();
}

In 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, the second method is more generic and almost the same as the first. Because of that, we can safely rewrite the 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 work.

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 the 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. The core difference is that correct delegate will be Action instead of Func so instead of one parameter, it will have two: 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 the second one. First, we have to create ExpressionParameter for new property value.

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

With this, we can change the returning value of lambda (if we are 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, it creates Action delegate with two parameters - sourceObjectParam and propertyValueParam - both are converted to correct type first. The above lines could be converted to the following lambda.

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

PropertySet overload with known property type is more specific than the above method, but at the same time, it will 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);
}

The last thing that should be fixed is null checking for GetMethod and SetMethod - after all it is already done in previous examples. This requires 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 or accessor does not exist (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. The best way to think 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 does 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. The simplest way to create it with a single call will be like below.

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

How to implement IndexerGet method? The 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, the way to obtain PropertyInfo is almost the same as for property - of course, there is a 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 of just one parameter with instance (like in properties) there is one more extra with index parameter. Besides that it is pretty much the same.

Ok, but what if indexer has more than one index? How about two or three? It is possible too and since IndexerGet method takes type parameters, we cannot make a more universal method that returns different delegates for 2, 3, 4 or more parameters. For each of those types of indexers, there is a necessity for other 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>));
}

The 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 return delegates for more indexes, up to 16 - it is the 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 the type of class. If we do not (because it is private or do 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. The difference is again with index parameter. Because it is an object, there is a 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 the 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 take an unspecified number of parameters. With that, we can easily rewrite most of the code for creating delegate, to more a universal version. We should write a 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();
}

The most important change is that this method takes an unspecified number of indexes types. The 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 methods 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 a 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 a 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, there would have to be a way to get all of indexer types in a uniform way. It is possible, for example, to write a 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 });

The 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 of all of that, it will be much slower than just call to getter, but if we do not have the luxury of more strict delegate (like Func<TSource, TIndex, TReturn>), it is the 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();
}

The main change from the previous methods is that we have a 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 a 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 the 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 are 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 the above indexers and the 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 result 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 than calling indexing operation on backend field, like in first indexer in TestClass, this difference will be even less visible. Another thing worth mentioning is that calling delegate with array instead of set of parameters make it much slower than the original indexer. In test indexer, it is about ten times slower. The difference is that big because indexer itself is just a single return operation when delegate will 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). On the other hand, if indexer would be more complex, the difference would be less visible. Anyway, still delegate is few times quicker than reflection call.

 

Improvements

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

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

Has anybody ever used that? Smile I do not think that it is very common, but it does 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 the 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 do not have null array returned from method GetIndexParameters. This way, we can find name for all indexers and then do more specific search for the one we really looking for. And end user of DelegatesFactory does not have to think about the 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 a 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 the 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 the 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 the method above. And new collections, callArgs and paramesExpressions, that allows us to pass appropriate values to lamba and setter calls. The first one, is a collection of indexes parameters expressions and value expression. The 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 a 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 the 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 takes type as type param - for known types at compile time. They will be called in the 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 the 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 a 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 a 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 has value type conversion to object is performed. Besides that, it is almost the same code as in the previous overload. Because of that, the 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 the 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 also write three overloads.

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

Since the first one can be easily rewritten as proxy to the second one, let's start the implementation with the 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 the 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);
}

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

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

The 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. The main change is extra parameter in all delegates. Because of that, we need not null first parameter (source instance) in Expression.Field call. Besides 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 a 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 uses Instance value of BindingFlags enumeration instead of Static one.

Let's start with the 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, casts 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 a 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 the 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 a similar result.

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

As you can see the 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 the 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 Expression.Assign and Expression.Field. Field has to take converted source parameter to instance type, instead of a null like in static field. Besides 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, the difference is noticeable. Probably instead of using the same method, but with parameter casting/without casting, the correct delegate is created by creating a new method that casts/converts parameters to appropriate types.

Ok, we will use FieldSet2 methods and not FieldSet overloads but after renaming them 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 a 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 to 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 FieldInfo type have property called IsInitOnly, which indicates if field can be set anytime or just during initialization - which is 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 the next article.

The code for article can be found on github and as Nuget package.



ViewFactory for Xamarin application

clock July 9, 2016 13: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 08: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 23, 2016 00: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 Style with Padding

clock April 22, 2016 06: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 23: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)



Smart string builder

clock February 22, 2014 04:16 by author n.podbielski

In this rare times when I was writing code that suppose to create large string from smaller chunks and with some non string parameters I was using StringBuilder class of course. Of course because string adding, or string concatenation is very costly when talking about memory utilization. It is because every time you do this:

var text = "Hello world!"+ "\n"+ "How are you?";

new string is created for every '+' operation in memory. Not a best way of doing strings creations. StringBuilder is better because it do not creates strings until you call .ToString method of StringBuilder class.

So instead of doing something like was shown above code should look something like follows:

var stringBuilder = new StringBuilder();
stringBuilder.Append("Hello world!");
stringBuilder.Append("\n");
stringBuilder.Append("How are you?");
Console.WriteLine(stringBuilder);

This is better but while writing this code I disliked of how much you have to type to just add another string to string builder object. I thought: can this be done better? In fact it can. And this is way I created SmartStringBuilder class.

Requirement was to have something like this:

var smartBuilder = new SmartStringBuilder();
smartBuilder += "Hello World!";
smartBuilder += "\n";
smartBuilder += "How are you?";
Console.WriteLine(smartBuilder);

Luckily C# alows to write custom behaviors for operators like '+'. To do this we can use special operator keyword in C#. For managing chunks of strings we will use private instance of StringBuilder class:

public class SmartStringBuilder
{
    private StringBuilder internalStringBuilder = new StringBuilder();

    public SmartStringBuilder() { }

    public SmartStringBuilder(string str)
    {
        internalStringBuilder.Append(str);
    }

    public override string ToString()
    {
        return internalStringBuilder.ToString();
    }

    public static SmartStringBuilder operator +(SmartStringBuilder smartBuilder, string addString)
    {
        smartBuilder.internalStringBuilder.Append(addString);
        return smartBuilder;
    }
}

This allows us to execute first 3 lines of 'requirements code'

var smartBuilder = new SmartStringBuilder();
smartBuilder += "Hello World!";
smartBuilder += "\n";
smartBuilder += "How are you?";

To allows using our new class us string in Console.WriteLine method (or any other method that takes string parameter) we need to add implicit casting operator to string type:

public static implicit operator string(SmartStringBuilder smartBuilder)
{
   return smartBuilder.ToString();
}

With our class defined like this we can execute following line:

Console.WriteLine(smartBuilder);

Another nice feature is possibility of adding values of other types to our builder with + sign. We can do this by adding + operator to our class for each of them. For example for int type this method would look like this:

public static SmartStringBuilder operator +(SmartStringBuilder smartBuilder, int number)
{
    smartBuilder.internalStringBuilder.Append(number);
    return smartBuilder;
}

This allows us to execute following line safely:

smartBuilder += 1;

Ideally would be to add possibility of formatting values of other types with format strings i.e.:

smartBuilder += ("format {0}", 1);

But this is impossible without changing C# language itslelf. Best thing we can do is to add AppendFormat method that executes method with the same name in internal StringBuilder object.

public void AppendFormat(string format, params object[] parameters)
{
     internalStringBuilder.AppendFormat(format, parameters);
}

Our whole class will look like this:

public class SmartStringBuilder
{

    private StringBuilder internalStringBuilder = new StringBuilder();

    public SmartStringBuilder() { }

    public SmartStringBuilder(string str)
    {
        internalStringBuilder.Append(str);
    }

    public override string ToString()
    {
        return internalStringBuilder.ToString();
    }

    public static implicit operator string(SmartStringBuilder smartBuilder)
    {
        return smartBuilder.ToString();
    }

    public static SmartStringBuilder operator +(SmartStringBuilder smartBuilder, string addString)
    {
        smartBuilder.internalStringBuilder.Append(addString);
        return smartBuilder;
    }

    public static SmartStringBuilder operator +(SmartStringBuilder smartBuilder, int number)
    {
        smartBuilder.internalStringBuilder.Append(number);
        return smartBuilder;
    }

    public void AppendFormat(string format, params object[] parameters)
    {
        internalStringBuilder.AppendFormat(format, parameters);
    }
}

That is it. Not much of magic but it simplifies string manipulation a little Smile.