• Migrating Database on App Startup with Entity Framework

    Entity Framework migrations are a great way to keep your database schema in sync with your data model. For local and development environments, automatically running migrations at startup can simplify your workflow significantly.

    Implementation with Environment Guards

    Let’s look at properly guarded migration code for different application types.

    Implementing this is ASP.NET

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
    
    var app = builder.Build();
    
    // Only migrate in development environment
    if (app.Environment.IsDevelopment())
    {
        using (var scope = app.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            try
            {
                var context = services.GetRequiredService<ApplicationDbContext>();
                context.Database.Migrate();
                Console.WriteLine("Database migrations applied successfully");
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "Error applying database migrations");
            }
        }
    }
    
    app.Run();

    Production Warning

    For production environments, never automatically apply migrations at startup. Instead:

    • Run migrations as a separate, controlled deployment step
    • Use database deployment tools or migration scripts
    • Ensure proper backups before schema changes

    Remember, this approach is intended only for local development and testing environments where database consistency is prioritized over startup performance and control.

  • Setting Window Size With Caliburn Micro

    This is something that has actually bugged me for a while. Once I figured it out, it annoyed me that I didn’t figure it out sooner.

    When displaying a window in Caliburn.Micro, you can set attributes about the Window object when calling it.

    So, let’s say you want to set the height and width on the window to 600 x 300:

    First, you would start with something like this:

    public class ShellViewModel : PropertyChangedBase, IShell
    {
        private readonly IWindowManager windowManager;
    
        public ShellViewModel()
        {
            this.windowManager = new WindowManager();
            this.windowManager.ShowWindow(new LameViewModel());
        }
    }

    There are two other fields on the ShowWindow method. The third parameter lets you dynamically set the attributes on the Window object.

    public class ShellViewModel : PropertyChangedBase, IShell
    {
        private readonly IWindowManager windowManager;
    
        public ShellViewModel()
        {
            this.windowManager = new WindowManager();
    
            dynamic settings = new ExpandoObject();
            settings.Height = 600;
            settings.Width = 300;
    
            this.windowManager.ShowWindow(new LameViewModel(), null, settings);
        }
    }

    I wish there was more information about working with this on the documentation, but there you have it.

  • Wiring Up Fluent Validation With WPF

    Update

    I originally wrote this proof of concept about 7 years ago early in my time with WPF. I published it on an earlier iteration of my blog via Github Gist and Wordpress (You can find the gist here). After which point I pretty much forgot out it.

    I recently came across the Gist and found that it has helped out a surprising number of people. So, it makes sense to me to pull this in to a blog and annotate it a bit better. If there is interest, I may make some more changes to streamline to examples and take advantage of newer C# features.

    Overview

    Fluent Validation is my favorite validation library for C#. It is pretty straightforward to use and it forces you to separate out the validation code into a separate class which IMHO generally makes the code cleaner.

    The library includes some pretty standard integrations with ASP.NET, but there never was a first class implementation that integrates a validator with a WPF view model. This post is a proof of concept that I put together to bridge that gap.

    Building the Validator

    For the purposes of demonstration. We’ll have a UserViewModel which has a property for Name, E-Mail, and Zip Code. So we’ll write a quick validator for the usual aspects of that data.

    using System.Text.RegularExpressions;
    using FluentValidation;
    using WpfFluentValidationExample.ViewModels;
    
    namespace WpfFluentValidationExample.Lib
    {
        public class UserValidator : AbstractValidator<UserViewModel>
        {
            public UserValidator()
            {
                RuleFor(user => user.Name)
                    .NotEmpty()
                    .WithMessage("Please Specify a Name.");
    
                RuleFor(user => user.Email)
                    .EmailAddress()
                    .WithMessage("Please Specify a Valid E-Mail Address");
    
                RuleFor(user => user.Zip)
                    .Must(BeAValidZip)
                    .WithMessage("Please Enter a Valid Zip Code");
            }
    
            private static bool BeAValidZip(string zip)
            {
                if (!string.IsNullOrEmpty(zip))
                {
                    var regex = new Regex(@"\d{5}");
                    return regex.IsMatch(zip);
                }
                return false;
            }
        }
    }

    Creating the View to Present the Validation

    Here is the view that I created to demonstrate this implementation.

    This is a standard form written in XAML with a few differences:

    • In the property binding for the text on the textboxes we can see that I added a “ValidatesOnDataErrors=True” clause.
    • On each one of those textboxes as well, I expanded out the Validation.Error template property with a stack panel which will slot in a validation error when one occurs.
    <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:viewModels="clr-namespace:WpfFluentValidationExample.ViewModels" x:Class="WpfFluentValidationExample.Views.UserView"
            Title="UserView" Height="300" MinWidth="500">
        <Window.DataContext>
            <viewModels:UserViewModel/>
        </Window.DataContext>
        <StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label Content="Name" Margin="10"/>
                <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="200" Margin="10">
                    <Validation.ErrorTemplate>
                        <ControlTemplate>
                            <StackPanel Orientation="Horizontal">
                                <AdornedElementPlaceholder x:Name="textBox"/>
                                <TextBlock Margin="10" Text="{Binding [0].ErrorContent}" Foreground="Red"/>
                            </StackPanel>
                        </ControlTemplate>
                    </Validation.ErrorTemplate>
                </TextBox>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label Content="E-Mail" Margin="10"/>
                <TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="200" Margin="10">
                    <Validation.ErrorTemplate>
                        <ControlTemplate>
                            <StackPanel Orientation="Horizontal">
                                <AdornedElementPlaceholder x:Name="textBox"/>
                                <TextBlock Margin="10" Text="{Binding [0].ErrorContent}" Foreground="Red"/>
                            </StackPanel>
                        </ControlTemplate>
                    </Validation.ErrorTemplate>
                </TextBox>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label Content="Zip" Margin="10"/>
                <TextBox Text="{Binding Zip, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="200" Margin="10">
                    <Validation.ErrorTemplate>
                        <ControlTemplate>
                            <StackPanel Orientation="Horizontal">
                                <!-- Placeholder for the TextBox itself -->
                                <AdornedElementPlaceholder x:Name="textBox"/>
                                <TextBlock Margin="10" Text="{Binding [0].ErrorContent}" Foreground="Red"/>
                            </StackPanel>
                        </ControlTemplate>
                    </Validation.ErrorTemplate>
                </TextBox>
            </StackPanel>
            <Button Margin="10">Submit</Button>
        </StackPanel>
    </Window>

    The Code Behind on the View

    Including this for the sake of completeness. Please ignore.

    using System.Windows;
    using WpfFluentValidationExample.ViewModels;
    
    namespace WpfFluentValidationExample.Views
    {
        /// <summary>
        /// Interaction logic for UserView.xaml
        /// </summary>
        public partial class UserView : Window
        {
            public UserView()
            {
                InitializeComponent();
                DataContext = new UserViewModel();
            }
        }
    }

    The Viewmodel

    The viewmodel is the integration point between the fluent validator, the data, and the view. Initially this looks like a standard viewmodel. We have a property for the name, email, and zip code.

    Closer to the bottom, you’ll find the integration for the validation:

    • There is the integration of the overloaded [] operator which matches up the property name with the validation.
    • There is also the addition of an Error string which combines together all the errors into a single string
    using System;
    using System.ComponentModel;
    using System.Linq;
    using WpfFluentValidationExample.Lib;
    
    namespace WpfFluentValidationExample.ViewModels
    {
        public class UserViewModel : INotifyPropertyChanged, IDataErrorInfo
        {
            private readonly UserValidator _userValidator = new UserValidator();
    
            private string _zip;
            private string _email;
            private string _name;
    
            public string Name
            {
                get { return _name; }
                set
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
    
            public string Email
            {
                get { return _email; }
                set
                {
                    _email = value;
                    OnPropertyChanged("Email");
                }
            }
    
            public string Zip
            {
                get { return _zip; }
                set
                {
                    _zip = value;
                    OnPropertyChanged("Zip");
                }
            }
    
            public string this[string columnName]
            {
                get
                {
                    var firstOrDefault = _userValidator.Validate(this).Errors.FirstOrDefault(p => p.PropertyName == columnName);
                    if (firstOrDefault != null)
                        return _userValidator != null ? firstOrDefault.ErrorMessage : "";
                    return "";
                }
            }
    
            public string Error
            {
                get
                {
                    if (_userValidator != null)
                    {
                        var results = _userValidator.Validate(this);
                        if (results != null && results.Errors.Any())
                        {
                            var errors = string.Join(Environment.NewLine, results.Errors.Select(x => x.ErrorMessage).ToArray());
                            return errors;
                        }
                    }
                    return string.Empty;
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged(string propertyName)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    Conclusion

    Thanks for sticking around to the end. I hope this helped you out improving the validation on your WPF application.

    If this helped you out, it would be helpful to star the Github Gist that is linked at the top of the post so that I know that I’m helping people out.

  • Getting Started With Hangfire

    Putting together this guide for testing out hangfire to fill in some of the gaps I found through creating a greenfield hangfire application.

    Setting up a database to test with

    Since I don’t have a SQL Server running that I can just attach to. I’ll have to run through the initial set up of SQL Express Edition

    1. Navigate to the website: https://www.microsoft.com/en-us/sql-server/sql-server-downloads
    2. Under the “Express” item at the bottom of the fold, hit the button “Download Now >”
    3. Run the installer
    4. Select “Basic” option
    5. Hit the “Accept” button without reading anything because I actually want to get some work done.
    6. Install it to the default directory

    Creating the Blank Project to Get Started

    1. Open up Visual Studio 2019
    2. Choose “Create a new Project”
    3. Search for asp.net project type. Since I would like to use the dashboard for this, I will have to use at least a .net core project. So, I selected the ASP.NET Core Empty project
    4. I named the application HangfireExperimentation
    5. Selected the Target Framework to be .NET 5.0 (Current).

    Setting up the Test Database for Hangfire to Use

    1. On the top menu go to View > SQL Server Object Explorer. This will open up a tab that allows you to navigate through the local database.
    2. From this view: Expand out SQL Server > {You’re localdb instance} > Databases
    3. Right Click on Databases and select “Add New Database”
    4. Name that Database HangfireExperimentation
    5. Expand out that database
    6. Right click on the database that was just created and select “Properties”
    7. In the properties tab, copy the connection string and save it somewhere to use later. Mine was something like:
    Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=HangfireExperimentation;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False

    Set up the Nuget Packages

    1. In the solution explorer, right click on the project and select “Manage nuget Packages…”
    2. Click on the “Browse” tab in the window
    3. Search for “Hangfire”
    4. Install the following packages
      • Hangfire.Core
      • Hangfire.SqlServer
      • Hangfire.AspNetCore

    Updating the appsettings.json file

    1. Open up the appsettings.json file
    2. Update the LogLevel to include hangfire
    3. Add the connection string that you saved earlier to the list of connection strings

    My appsettings.json file ended up looking like this:

    {
    "Logging": {
        "LogLevel": {
        "Default": "Information",
        "Microsoft": "Warning",
        "Microsoft.Hosting.Lifetime": "Information",
        "Hangfire": "Information"
        }
    },
    "ConnectionStrings": {
        "HangfireConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=HangfireExperimentation;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
    },
    "AllowedHosts": "*"
    }

    Update the Startup.cs file

    1. Update the ConfigureServices() method so that it looks like this:
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHangfire(configuration => configuration
            .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
            .UseSimpleAssemblyNameTypeSerializer()
            .UseRecommendedSerializerSettings()
            .UseSqlServerStorage(ConfigurationManager.ConnectionStrings["HangfireConnection"].ConnectionString, new SqlServerStorageOptions
            {
                CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
                SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
                QueuePollInterval = TimeSpan.Zero,
                UseRecommendedIsolationLevel = true,
                DisableGlobalLocks = true
            }));
    
        services.AddHangfireServer();
    
        services.AddMvc(option => option.EnableEndpointRouting = false);
    }
    1. Run through and add the missing references

    2. Add in the Configuration field that ConfigureServices(…) uses to get the connection string

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    
    public IConfiguration Configuration { get; }
    1. Update the Configure(…) method to look like this:
    public void Configure(IApplicationBuilder app, 
        IWebHostEnvironment env, 
        IBackgroundJobClient backgroundJobs)
    {
        app.UseStaticFiles();
    
        app.UseHangfireDashboard();
        backgroundJobs.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));
    
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

    Testing things out

    1. Hit play on Visual Studio
    2. Since this was created with blank project
    3. Navigate to the hangfire dashboard. My url was: https://localhost:44321/hangfire
    4. PROFIT?!!
  • Activator.CreateInstance Alternatives with Benchmarks

    .NET provides multiple ways of generating objects at runtime. Each of these options offer their own trades offs in terms of performance. I will demonstrate that not only are there great performance gains to be had over Activator.CreateInstance(…), but I will also show that there are nuances to how you set up these classes that can dramatically effect performance.

    Why is this important?

    While there may be more applications, two examples that I can think of that rely on generating objects at runtime are game development frameworks and IOC (inversion of control) containers. Many game develoment environments are set up to create and manipulate objects that are dynamically loaded in. Being able to do that quickly is super important especially with the recent boom of game development in C# as of late.

    IOC containers also need to be able to generate objects quickly because applications that use them will typically rely on the framework to generate most of the objects in the application.

    I decided to put together this analysis because I recently started working on a legacy codebase that relies a great deal on Activater.CreateInstance for instantiating objects. Swapping out the implementation of Activater.CreateInstance could load to some better performance. I may report back with my findings.

    Show me the code!

    I want you to be able to verify my results if you wish. As such, I’ve put together a github repo with all the code I used to do these benchmarks: https://github.com/holymoo/DynamicObjectCreationBenchmark

    In addition to this, I’m going to break down each segment that I tested in these benchmarks.

    the ’new’ operator

    The new operator is the normal way of creating new objects in C#.

    public static class NewBuilder
    {
        public static TestObject Build()
        {
            return new TestObject();
        }
    }

    This is included because it will serve as our baseline to show us how much performance we are losing by dynamically generating our objects at runtime.

    Activator.CreateInstance

    This is the simplest and most common way of generating objects at runtime. It’s simple to write and is generally performant enough for most things, but we can do better.

    Create Instance without a Template

    public static class ActivatorCreateBuilderWithoutGeneric
    {
        public static TestObject Build()
        {
            return (TestObject)Activator.CreateInstance(typeof(TestObject));
        }
    }

    Create Instance with a Template

    public static class ActivatorCreateBuilderWithGeneric
    {
        public static TestObject Build()
        {
            return Activator.CreateInstance<TestObject>();
        }
    }

    I’m including both the templated and the non-templated version in this test because there can be performance implications demonstrated in the other methods.

    Serialization

    These methods rely on combination of the System.Reflection and System.Runtime.Serialization namespaces. I believe these methods rely primarily on serialization to generate the objects; however, I didn’t look at the source code.

    Without a template, without caching

    public static class FormatterServicesBuilderWithoutCachingWithoutGeneric
    {
        public static object Build(Type t)
        {
            var o = FormatterServices.GetUninitializedObject(t);
            var ctor = t.GetConstructors()[0];
            return ctor.Invoke(o, new object[] { });
        }
    }

    Without a template, with caching

    public static class FormatterServicesBuilderWithCachingWithoutGeneric
    {
        private static readonly Dictionary<Type, ConstructorInfo> cache = 
            new Dictionary<Type, ConstructorInfo>();
    
        public static object Build(Type t)
        {
            if (cache.TryGetValue(t, out ConstructorInfo ctor))
            {
                var o = FormatterServices.GetUninitializedObject(t);
                return ctor.Invoke(o, new object[] { });
            }
            else
            {
                var o = FormatterServices.GetUninitializedObject(t);
                ctor = t.GetConstructors()[0];
                cache.Add(t, ctor);
                return ctor.Invoke(o, new object[] { });
            }
        }
    }

    With a template, without caching

    public static class FormatterServicesBuilderWithoutCachingWithGeneric<T>
    {
        public static T Build()
        {
            var t = typeof(T);
            var o = FormatterServices.GetUninitializedObject(t);
            var ctor = t.GetConstructors()[0];
            return (T)ctor.Invoke(o, new object[] { });
        }
    }

    With a template, with caching

    public static class FormatterServicesBuilderWithCachingWithGeneric<T>
        {
            private static readonly Type t = typeof(T); 
            private static readonly ConstructorInfo ctor = t.GetConstructors()[0];
    
            public static T Build()
            {
                var o = FormatterServices.GetUninitializedObject(t);
                return (T)ctor.Invoke(o, new object[] { });
            }
        }

    Emitting IL

    These methods are often referenced as being the fastest way to generate objects at runtime. To a certain degree, that is true; however, there are some nuances to the topic that we will see when it comes to the benchmarks.

    Without a template, without caching

    public static class MsilBuilderWithoutCachingWithoutGeneric
    {
        public delegate object DynamicObjectActivator();
    
        public static object Build(Type t)
        {
            var dynamicMethod = new DynamicMethod("CreateInstance", t, Type.EmptyTypes, true);
            var ilGenerator = dynamicMethod.GetILGenerator();
            ilGenerator.Emit(OpCodes.Nop);
            ConstructorInfo emptyConstructor = t.GetConstructor(Type.EmptyTypes);
            ilGenerator.Emit(OpCodes.Newobj, emptyConstructor);
            ilGenerator.Emit(OpCodes.Ret);
            var del = (DynamicObjectActivator)dynamicMethod.CreateDelegate(typeof(DynamicObjectActivator));
            return del();
        }
    }

    Without a template, with caching

    public static class MsilBuilderWithCachingWithoutGeneric
    {
        public delegate object DynamicObjectActivator();
        private static readonly Dictionary<Type, DynamicObjectActivator> cache = new Dictionary<Type, DynamicObjectActivator>();
    
        public static object Build(Type t)
        {
            if(cache.TryGetValue(t, out DynamicObjectActivator value))
            {
                return value();
            }
    
            var dynamicMethod = new DynamicMethod("CreateInstance", t, Type.EmptyTypes, true);
            var ilGenerator = dynamicMethod.GetILGenerator();
            ilGenerator.Emit(OpCodes.Nop);
            ConstructorInfo emptyConstructor = t.GetConstructor(Type.EmptyTypes);
            ilGenerator.Emit(OpCodes.Newobj, emptyConstructor);
            ilGenerator.Emit(OpCodes.Ret);
    
            var del = (DynamicObjectActivator)dynamicMethod.CreateDelegate(typeof(DynamicObjectActivator));
            cache.Add(t, del);
    
            return del();
        }
    }

    With a template, without caching

    public static class MsilBuilderWithoutCachingWithoutGeneric
    {
        public delegate object DynamicObjectActivator();
    
        public static object Build(Type t)
        {
            var dynamicMethod = new DynamicMethod("CreateInstance", t, Type.EmptyTypes, true);
            var ilGenerator = dynamicMethod.GetILGenerator();
            ilGenerator.Emit(OpCodes.Nop);
            ConstructorInfo emptyConstructor = t.GetConstructor(Type.EmptyTypes);
            ilGenerator.Emit(OpCodes.Newobj, emptyConstructor);
            ilGenerator.Emit(OpCodes.Ret);
            var del = (DynamicObjectActivator)dynamicMethod.CreateDelegate(typeof(DynamicObjectActivator));
            return del();
        }
    }

    With a template, with caching

    public static class MsilBuilderWithCachingWithGeneric<T>
    {
        private static Type t = typeof(T);
        private static Func<T> func;
    
        public static T Build()
        {
            if(func != null)
            {
                return func();
            }
    
            var dynamicMethod = new DynamicMethod("CreateInstance", t, Type.EmptyTypes, true);
            var ilGenerator = dynamicMethod.GetILGenerator();
            ilGenerator.Emit(OpCodes.Nop);
            ConstructorInfo emptyConstructor = t.GetConstructor(Type.EmptyTypes);
            ilGenerator.Emit(OpCodes.Newobj, emptyConstructor);
            ilGenerator.Emit(OpCodes.Ret);
    
            func = (Func<T>)dynamicMethod.CreateDelegate(typeof(Func<T>));
            return func();
        }
    }

    Compiled Linq method

    This is the final benchmark that we’ll be doing for this post. This is also often referred to the fastest way to generate an object dynamically at runtime. While this may be true, there are some nuances to this much like generating IL at runtime.

    With a template, without caching

    public static class LinqBuilderWithoutCachingWithGeneric
    {
        public static T Build<T>()
        {
            var t = typeof(T);
            var ex = new Expression[] { Expression.New(t) };
            var block = Expression.Block(t, ex);
            var builder = Expression.Lambda<Func<T>>(block).Compile();
            return builder();
        }
    }

    With a template, with caching

    public static class LinqBuilderWithCachingWithGeneric<T>
    {
        private static readonly Type t = typeof(T);
        private static readonly Expression[] ex = new Expression[] { Expression.New(t) };
        private static readonly BlockExpression block = Expression.Block(t, ex);
        private static readonly Func<T> builder = Expression.Lambda<Func<T>>(block).Compile();
    
        public static T Build()
        {
            return builder();
        }
    }

    The actual testing code

    Since I am a noob to writing benchmark code, I decided to use the framework benchmark .net for doing this performance analysis. The framework was really nice for providing easy testing and making sure the environment was set up to not introduce side effects that could skew the results.

    The code was compiled in x64 with the /optimize flag. In addition to this the benchmarks were run without the debugger attached.

    [ClrJob]
    [RPlotExporter, RankColumn]
    public class TheActualBenchmark
    {
        [Params(1000000)]
        public int N;
    
        [Benchmark]
        public TestObject StandardNew() => NewBuilder.Build();
    
        [Benchmark]
        public TestObject ActivatorCreateBuilderWithoutGenericTest() => 
            ActivatorCreateBuilderWithoutGeneric.Build();
    
        [Benchmark]
        public TestObject ActivatorCreateBuilderWithGenericTest() => 
            ActivatorCreateBuilderWithGeneric.Build();
    
        [Benchmark]
        public TestObject FormatterServicesBuilderWithoutCachingWithoutGenericTest() => 
            (TestObject)FormatterServicesBuilderWithoutCachingWithoutGeneric
                .Build(typeof(TestObject));
    
        [Benchmark]
        public TestObject FormatterServicesBuilderWithCachingWithoutGenericTest() =>
            (TestObject)FormatterServicesBuilderWithoutCachingWithoutGeneric
                .Build(typeof(TestObject));
    
        [Benchmark]
        public TestObject FormatterServicesBuilderWithoutCachingWithGenericTest() =>
            FormatterServicesBuilderWithoutCachingWithGeneric<TestObject>
                .Build();
    
        [Benchmark]
        public TestObject FormatterServicesBuilderWithCachingWithGenericTest() =>
            FormatterServicesBuilderWithCachingWithGeneric<TestObject>.Build();
    
        [Benchmark]
        public TestObject MsilBuilderWithoutCachingWithoutGenericTest() =>
            (TestObject)MsilBuilderWithoutCachingWithoutGeneric
                .Build(typeof(TestObject));
    
        [Benchmark]
        public TestObject MsilBuilderWithCachingWithoutGenericTest() =>
            (TestObject)MsilBuilderWithCachingWithoutGeneric
                .Build(typeof(TestObject));
    
        [Benchmark]
        public TestObject MsilBuilderWithoutCachingWithGenericTest() =>
            MsilBuilderWithoutCachingWithGeneric<TestObject>.Build();
    
        [Benchmark]
        public TestObject MsilBuilderWithCachingWithGeneric() =>
            MsilBuilderWithCachingWithGeneric<TestObject>.Build();
    
        [Benchmark]
        public TestObject LinqBuilderWithoutCachingWithGenericTest() =>
            LinqBuilderWithoutCachingWithGeneric.Build<TestObject>();
    
        [Benchmark]
        public TestObject LinqBuilderWithCachingWithGenericTest() =>
            LinqBuilderWithCachingWithGeneric<TestObject>.Build();
    }

    Show me the results!

    RankMethodMeanStdDev
    1Standard New2.057 ns0.0291 ns
    2Linq Builder w/ Caching w/ Generic10.443 ns0.0219 ns
    3Msil Builder w/ Caching w/ Generic18.629 ns0.0363 ns
    4MsilBuilderWithCaching w/o Generic32.084 ns0.1033 ns
    5ActivatorCreateBuilder w/o Generic37.118 ns0.1491 ns
    6ActivatorCreateBuilder w/ Generic44.275 ns0.1224 ns
    7FormatterServicesBuilder v Caching w/ Generic157.669 ns1.6577 ns
    8FormatterServicesBuilder w/o Caching w/o Generic203.001 ns0.4439 ns
    9FormatterServicesBuilder w/ Caching w/o Generic205.826 ns0.3978 ns
    10FormatterServicesBuilder w/o Caching w/ Generic206.732 ns0.3488 ns
    11MsilBuilder w/o Caching w/ Generic61,932.402 ns764.5614 ns
    12MsilBuilder w/o Caching w/o Generic62,795.093 ns494.1148 ns
    13LinqBuilder w/o Caching w/ Generic76,461.628 ns998.5591 ns

    Based of of these results we can draw some pretty solid conclusions

    1. The fastest way by far to create an object is by using the new operator. Using the new operator yields performance this is about 18 times faster than Activater.CreateInstance and about 5 times faster than our fastest dynamic implementation.
    2. If you can specify the class via a generic, your fastest implementation is going to be using the Linq builder implementation with caching. It’s performance was about three times faster than Activator.CreateInstance.
    3. If you have to specify your type via the typeof operator, than the fastest implementation is going to be with dynamically generating Msil code. Using this method produced objects in about half the time compared to Activater.CreateInstance.
    4. If you’re going to try writing your own object creation code, please use caching. None of the implementaions tested were about to compete with Activator.CreateInstance unless they used some form of method caching. Furthermore, without caching our fastest implementation ended up becoming our slowest method of dynamically generating an object.
    5. If you plan on only creating on object once, you’re better off using Activator.CreateInstance. The method that performed the best in this test did so because they were able to cache the process of building the object.
    6. Formatter services should never be used for building objects at runtime.

    Thanks!

    I really appreciate you taking the time to read to the end. This information took several days to code, tabulate, and review. I hope you found it helpful.