TypeScript for C# and .NET Core Developers Review

I finished reading Hands-On TypeScript for C# and .NET Core Developers by Francesco Abbruzzese (@f_abbruzzese) for Packt Publishing. As the name states, it is about TypeScript (and JavaScript) and also very much about Angular.

The book is structured like this:

  1. First chapter explains what is TypeScript (version 2.8.3), how to install it using NPM or the SDK, how to create your first project, basic configuration options, the type system and syntax; at all times, it relates the TypeScript syntax with the recent ECMAScript versions, of which TypeScript is a superset
  2. The second one talks about type declaration, including interfaces, classes, unions, tuples, arrays and so on. It also covers operations over types, such as destructuring and spreads. Finally, it presents functions in TypeScript, how to mimic overloading and have optional arguments
  3. Chapter 3 covers DOM manipulation. This is probably something that seasoned web/JavaScript developers are quite familiar with, but, most importantly, it also introduces declaration files
  4. In chapter 4 we learn how to make effective use of classes and interfaces, declare visibility levels and modifiers, and how type compatibility works
  5. Generics is the topic of chapter 5, how to declare generic types and functions and how to enforce constraints
  6. This chapter talks about modules and namespaces, the different ways by which we can resolve and load modules, and also about TypeScript type declarations, which are used to call untyped JavaScript code
  7. Here we learn how to integrate the WebPack bundler and minifier with ASP.NET Core and how we can enable debugging of the source code in Visual Studio
  8. A very important chapter, here we get an overview on how to write reusable libraries and make them available on NPM. Testing goes together with reusability, so we learn how to use Jasmine to unit test our code
  9. In this chapter we learn about symbols, the TypeScript equivalent to decorators in Aspect-Oriented Programming, generator functions and iterators and also promises, used for asynchronous invocations. Not exactly related, but it also covers the fetch API, used for modern AJAX-style interactions
  10. Chapter 10 presents the ASP.NET Core project template for Angular using TypeScript, describes the Angular architecture and key concepts
  11. This chapter teaches us how to interact with form fields, including validations, how the Angular lifecycle works and how to achieve two-way communication, data binding and piping between components
  12. This one presents some advanced Angular features, such as custom attribute and structural directives, which are then used to create animations by doing DOM manipulation
  13. Lastly, this chapter explains what is dependency injection and its benefits and how we can leverage it with TypeScript and Angular. It also describes how we can localize messages and use HTTP-related modules for interaction with external services. Most importantly, it presents the basis of Angular routing and navigation, a must-have for any complex application, and ends with an overview of testing for

At the end of each chapter there is a summary which highlights the key aspects that were introduced in it, poses 10 questions, which are answered in the Assessments chapter.

The book covers TypeScript 2.8.3, which is relatively old by now, but given the pace that TypeScript versions come out, it can hardly surprise us. Some new stuff in TS is missing, of course, but I guess this will always happen. It is essentially a book about TypeScript and Angular, but of course also covers Node.js and, obviously, JavaScript itself. .NET Core here is discussed as leverage to deploy and compile client-side code. The book is quite comprehensive and was actually an interesting read and I definitely learnt a lot.

The source code can be found in GitHub here: https://github.com/PacktPublishing/Hands-On-TypeScript-for-CSharp-and-.NET-Core-Developers.

If you got interested, please go get if from the Packt Publishing site: https://www.packtpub.com/application-development/hands-typescript-c-and-net-core-developers.

Now Reading: Hands-On TypeScript for C# and .NET Core Developers

I started reading a book by my MVP colleague Francesco Abbruzzese (@f_abbruzzese) on C# and TypeScript: Hands-On TypeScript for C# and .NET Core Developers. So far, it seems an interesting reading! Will write a review about it here, once I finish reading it. In case you want to know more, go get if from the Packt Publishing site: https://www.packtpub.com/application-development/hands-typescript-c-and-net-core-developers.

Succinctly Series Readers Awards

image

My e-book Entity Framework Core Succinctly was silver winner on the Succinctly Series Readers Awards!

Many thanks to all who voted for it! And congratulations to Joseph D. Booth for winning the gold award for his Natural Language Processing Succinctly and to Alessando Del Sole (@progalex) for his bronze award for Xamarin.Forms Succinctly!

https://www.syncfusion.com/awards/succinctlyseries/2018succinctlyreadersawards

Performance in .NET – Part 3

Introduction

This post is part of a series on performance in .NET. See the first one on object instantiation and the second on property copying here. This time I’m going to talk about collections, but focusing on the performance side.

Collections

Back in 2009 (!) I wrote a blog post, which I updated a couple of times, about .NET collection types. Essentially, my point was – is – that you should pick the right collection for the job that you have at hands. This post is still up to date.

How many of us don’t by default just choose List<T> when there is need for a general-purpose collection? I certainly do, at times… Well, it turns out that this may or may not be what we need. Let me give a few examples.

List<T> is an array-based collection, which means that it is probably the best if you are going to iterate through items one at a time, sequentially, but it is not so good if you want to remove items from a random position other than the list’s end, because this causes a whole new array to be instantiated in memory, and all items (except the one that you wish to remove, of course) from the original list to be copied into the new one. It’s the same problem with random inserts at any given position, other than the end, and only if the initial capacity isn’t exceeded.

For operations where random inserts and deletes are required, LinkedList<T> is a much better choice as it does not require the instantiation of new arrays and the memory copy. It does that, however, at the expense of a slightly poorer performance in list traversal.

What about duplicates? With the previous list implementations, if we don’t want to allow duplicates, we need to check one by one, which is a PITA. Luckily, the .NET BCL has an implementation of a mathematical set which automatically excludes duplicates. One implementation is HashSet<T>, which is an indexed collection that uses each object’s GetHashCode method to figure out if the object already exists in the collection; needless to say, this method must be properly implemented.

Talking about indexed collections, if we want to be able to rapidly get to one element – or a number of elements – by some key, .NET has that as well: Dictionary<TKey, TValue> for storing a single value per unique key. The key can be of whatever type we want. This one also offers good performance when it comes to retrieving, adding, removing or modifying a single item.

Then we have LIFO and FIFO implementations in the form of the Stack<T> and Queue<T> types, which are optimized for adding items at the top or the bottom of the list, respectively, and don’t even allow other kinds of operations other than traversal. Internally they also use a linked-list approach.

Bits have their own specialized collections, BitArray and BitVector32. The latter only works with up to 32 bits and it probably provides the fastest performance of the two, according to Microsoft:

BitVector32 is more efficient than BitArray for Boolean values and small integers that are used internally. A BitArray can grow indefinitely as needed, but it has the memory and performance overhead that a class instance requires. In contrast, a BitVector32 uses only 32 bits.

Finally, Microsoft makes available thread-safe collections that are thread-safe in nature and therefore do not need any thread synchronization mechanisms, which makes them faster than if we had to roll out our own thread synchronization. They include thread-safe dictionaries (ConcurrentDictionary<TKey, TValue>), queues (ConcurrentQueue<T>), stacks (ConcurrentStack<T>) and general-purpose lists (BlockingCollection<T>).

Conclusion

I didn’t go through all the collection classes available, for that you can refer to my previous post.

The point I want to make with this post is:

  • Pick the right collection for the job; use the 80-20 rule and try to understand what the most common usage for your collection will be; do not just go blindly with List<T> or similar
  • Always expose collections publicly though interfaces or base classes that only show the bare minimum required, so that you can swap out the implementation should you need to
  • And, of course, measure your usage so that you can make opinionated decisions.

If performance is not an issue, by all means, forget about this and keep on doing what you are already doing and works for you.

Java vs C# – Part 3

Introduction

This is the third in a series of posts about the similarities and differences between C# (and .NET, to some extent) and Java. You can find the first one here and the second one here.

Again, with this I do not intent to demonstrate that one is superior to the other – totally – as I really like both platforms, even though I work mostly with C# and .NET. This is merely an exercise to show these differences and maybe it can be useful to someone who is learning one or the other. If you find something that you think is wrong, please let me know!

Keyword Usage

In Java, it is not possible to use reserved words, or keywords, such as class, public, etc, as variables, parameters or field names. In C# you can if you prefix it with @:. For example:

var @class = “My Class”;

Object Class

The Object class is the root of both type hierarchies in both Java and .NET. The two are pretty similar, with some remarkable exceptions. All of the following have exactly identical behavior:

Java .NET
clone MemberwiseClone
getClass GetType
equals Equals
hashCode GetHashCode
finalize Finalize
toString ToString

.NET does not offer methods corresponding to notify, notifyAll or wait. On the other hand, Java does not offer a method like ReferenceEquals.

Tuples

Recent versions of C# lets us return tuples, which are sets of values combined together ad hoc, but not inside a type definition. For example, should you wish to return a coordinate from a method, you could do this:

(double x, double y) GetCoordinates()

{

double x = …;

double y = …;

return (x, y);

}

It is also possible to “deconstruct” a class into a tuple, by providing a proper Deconstruct method:

public class Coordinate

{

public void Deconstruct(out double x, out double y)

{

x = …;

y = …;

}

}

Coordinate coord = …;

(double x, double y) = coord;

You can have as many Deconstruct methods you like, provided their signatures are different. For now, at least, Java is still lacking this functionality.

nameof

C# lets us use the nameof keyword to obtain a strongly-typed name of a class, method, property, field or parameter. It is very useful because it is refactor-friendly: should you change the name of the target, you also change the value that is being assigned. An example:

var className = nameof(MyClass); //”MyClass”

var fieldName = nameof(MyClass.MyField); //”MyField”

Mind you, only the “final” piece is returned, for example, if you use nameof with a fully qualified type name, you’ll only get the type name.

Friend Assemblies

As you know, internal classes and their methods are not available outside the current assembly/namespace. In C#/.NET, however, we can make these internals available to other assemblies by applying the InternalsVisibleToAttribute attribute to the assembly that we want to make available. These are called friend assemblies. For example:

[assembly:InternalsVisibleTo(“My.Assembly”)]

Async/Await

C# 5 introduced a new asynchronous programming model around the async and await keywords. I won’t go into the details of it but essentially it simplifies asynchronous programming a lot, preventing the usage of a lot of boilerplate code. It goes like this:

async Task<int> Compute(int a, int b) { … }

var result = await Compute(1, 2);

Import Methods

In C# we can import public static methods from public classes, which means, we can use them without prefacing them with the name of the class. The syntax is like this:

using static System.Environment;

and the usage:

var path = GetEnvironmentVariable(“PATH”);

Local Functions

.NET allows us to define local functions, that is, functions that exist only in the scope of methods. They are similar to lambda functions, with some remarkable differences, among which:

  • They can have attributes applied to its parameters
  • They can have ref, out and other kind of parameters
  • They can be asynchronous

An example:

void SomeMethod()

{

int sum(int a, int b) => a + b;

var x = sum(1, 2);

}

The closest that Java offers is anonymous classes, which are actually pretty cool, IMO.

Asserts

Java offers the assert keyword as part of the language, this has no equivalent in .NET. An assert evaluates a Boolean condition which, if not found to be true, throws an error:

assert speed < SPEED_OF_LIGHT;

Forgot to say, assertions can be disabled, which means, they are turned into no-ops.

Next Steps

I still have a couple of things to talk about, so be prepared for a future post!

As always, do let me know if you think I got anything wrong or you wish me to clarify something.

.NET Core Service Provider Gotchas and Less-Known Features

Introduction

In this post I’m going to talk about a few gotchas with the .NET Core’s built-in inversion of control (IoC) / service provider (SP)/dependency injection (DI) library. It is made available as the Microsoft.Extensions.DependencyInjection NuGet package.

I wrote another post some time ago, but this one supersedes it, in many ways.

Extension Methods

The single method exposed by the IServiceProvider interface, GetService, is not strongly typed. If you add a using statement for Microsoft.Extensions.DependencyInjection, you’ll get a few ones that are:

  • GetRequiredService<T>: tries to retrieve a service that is registered under the type of the generic template parameter and throws an exception if one cannot be found; if it is, it is cast to the template parameter;
  • GetService<T>: retrieves a service and casts it to the template parameter; if no service is found, null is returned;
  • GetServices<T>: returns all services registered as the template parameter type, cast appropriately.

Using a Different Service Provider

You are not forced to use the built-in service provider; you can use anyone you like, as long as it exposes an IServiceProvider implementation. You just need to return this implementation from the ConfigureServices method, which normally does not return anything:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
//return an implementation of IServiceProvider
}

Why would you want to do that, you may ask? Well, there are service providers out there that offer much more interesting features than Microsoft’s (for example, more lifetimes), and this has a reason: Microsoft kept his simple on purpose.

Multiple Registrations

You may not have realized that you can register any number of implementations for a given service, even with different lifetimes:

services.AddTransient<IService, ServiceA>();
services.AddScoped<IService, ServiceB>();

So, what happens when you ask for an implementation for IService? Well, you get the last one registered, in this case, ServiceB. However, you can ask for all the implementations, if you call GetServices<T>.

Registration Factories

You can specify how a service implementation is constructed when you register a service, and it can depend upon other services that are also registered in the service provider:

services.AddTransient<IService>(sp => new ServiceImpl(sp.GetRequiredService<IOtherService>));

Don’t worry about registration order: IOtherService will only be required once IService is retrieved.

Lifetime Dependencies

You cannot have a Singleton registration depend upon a Scoped service. This makes sense, if you think about it, as a singleton has a much longer lifetime than a scoped service.

Nested Scopes

You can create nested scopes at any time and retrieve services from them. If you are using the extension methods in the Microsoft.Extensions.DependencyInjection namespace, it’s as easy as this:

using (var scope = serviceProvider.CreateScope())
{
    var svc = scope.ServiceProvider.GetRequiredService<IService>();
}

The CreateScope method comes from the IServiceScopeFactory implementation that is registered automatically by the dependency injection implementation. See next for implications of this.

Why is this needed? Because of lifetime dependencies: using this approach you can instantiate a service marked as a singleton that takes as a parameter a scoped one, inside a scope.

Dispose Pattern

All services instantiated using the Scoped or Transient lifetimes that implement the IDisposable interface will have their Dispose methods called at the end of the request – or the nested scope (when it is disposed). The root service provider is only disposed with the app itself.

Scope Validation

The built-in service provider validates the registrations so that a singleton does not depend on a scoped registration. This has the effect of preventing retrieving services in the Configure method, through IApplicationBuilder.ApplicationServices, that are not transient or singletons.

If, however, you think you know what you’re doing, you can bypass this validation:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
//add services
return services.BuildServiceProvider(validateScopes: false);
}

As I said before, the other alternative is creating a scope and instantiating your singleton service inside the scope. This will always work.

Injecting Services

ASP.NET Core only supports constructor:

public HomeController(IService svc)
{
}

and parameter:

public IActionResult Index([FromServices] IService svc)
{
}

inheritance, but not property, in controllers and Razor Pages. You can achieve that through actions or conventions. Another option is to use the Service Locator pattern.

Service Locator

You can retrieve any registered services from HttpContext.RequestServices, so whenever you have a reference to an HttpContext, you’re good. From the Configure method, you can also retrieve services from IApplicationBuilder.ApplicationServices, but not scoped ones (read the previous topics). However, it is generally accepted that you should prefer constructor or parameter injection over the Service Locator approach.

Conclusion

Although the service provider that comes with .NET Core is OK for most scenarios, it is clearly insufficient for a number of others. These include:

  • Other lifetimes, such as, per resolve-context, per thread, etc;
  • Property injection;
  • Lazy<T> support;
  • Named registrations;
  • Automatic discovery and configuration of services;
  • Child containers.

You should consider a more featured DI library, and there are many out there, if you need any of these.

Integrating Managed Extensibility Framework with the .NET Service Provider

Introduction

It seems I’m in the mood for Managed Extensibility Framework: second post in a week about it! This time, I’m going to talk about how we can integrate it with the .NET Core’s service provider/dependency injection (DI) library (Microsoft.Extensions.DependencyInjection).

Mind you, this will apply to both ASP.NET Core and .NET Core console apps.

Locating Services

We’ve seen before how we can find all types that match a given interface:

public static class ContainerConfigurationExtensions     {         public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)         {             return WithAssembliesInPath(configuration, path, null, searchOption);         }         public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, AttributedModelProvider conventions, SearchOption searchOption = SearchOption.TopDirectoryOnly)         {             var assemblyFiles = Directory                 .GetFiles(path, "*.dll", searchOption);             var assemblies = assemblyFiles                 .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath);             configuration = configuration.WithAssemblies(assemblies, conventions);             return configuration;         }     }

Service Registration

The next step is picking up all of the found types and registering them with the DI:

public static class ServiceCollectionExtensions     {         public static IServiceCollection AddFromAssembliesInPath<T>(this IServiceCollection services, ServiceLifetime lifetime, string path = null) where T : class         {             var factory = new ExportFactory<T, object>(() => new Tuple<T, Action>(Activator.CreateInstance<T>(), () => { }), new object());             var conventions = new ConventionBuilder();             var builder = conventions                 .ForTypesDerivedFrom<T>()                 .Export<T>();             if (lifetime == ServiceLifetime.Singleton)             {                 builder = builder.Shared();             }             path = path ?? AppContext.BaseDirectory;             var configuration = new ContainerConfiguration()                 .WithAssembliesInPath(path, conventions);             using (var container = configuration.CreateContainer())             {                 var svcs = container.GetExports<Lazy<T>>();                 foreach (var svc in svcs)                 {                     services.Add(new ServiceDescriptor(typeof(T), sp => svc.Value, lifetime));                 }             }             return services;         }         public static IServiceCollection AddSingletonFromAssembliesInPath<T>(this IServiceCollection services, string path = null) where T : class         {             return AddFromAssembliesInPath<T>(services, ServiceLifetime.Singleton, path);         }         public static IServiceCollection AddScopedFromAssembliesInPath<T>(this IServiceCollection services, string path = null) where T : class         {             return AddFromAssembliesInPath<T>(services, ServiceLifetime.Scoped, path);         }         public static IServiceCollection AddTransientFromAssembliesInPath<T>(this IServiceCollection services, string path = null) where T : class         {             return AddFromAssembliesInPath<T>(services, ServiceLifetime.Transient, path);         }     }

The AddFromAssembliesInPath extension method is what does all the work; it leverages the previous WithAssembliesInPath method to locate all types that match a given interface, in the assemblies inside a specific folder (which can be the current one). AddSingletonFromAssembliesInPath, AddScopedFromAssembliesInPath and AddTransientFromAssembliesInPath are merely here to make your life a (little bit) easier. Although MEF only supports singletons (Shared) and transient (Non-shared) lifetimes, with this approach

Notice how MEF let’s us resolve Lazy<T> instances besides T. This is pretty cool, as we can delay object instantiation to a later stage, when the object is actually needed. A word of caution: the instantiation will actually be done by MEF, not by the .NET Core DI, so you won’t have constructor injection.

Putting it all Together

So, armed with these two extension methods, we can add this to the ConfigureServices method of your ASP.NET Core app (or wherever you populate your service provider):

services.AddTransientFromAssembliesInPath<IPlugin>();

Here IPlugin is just some interface, nothing to do with the one described in the previous post. After this, you should be able to inject all of the actual implementations:

public class HomeController : Controller

{

public HomeController(IEnumerable<IPlugin> plugins) { … }

}

Dynamically Loading Middleware in ASP.NET Core

Introduction

The concept of middleware has been around since ASP.NET MVC (pre-Core) and OWIN. Essentially, a middleware component lives in a pipeline and handles requests and acts as a chain of responsibility, delegating to any subsequent middleware components registered in the pipeline after itself. The following image (taken from the Microsoft site) shows this.

Image result for asp.net core middleware

MVC itself is implemented as a middleware component, as is redirection, exception handling, buffering, etc.

A middleware component can be added in several ways, but in ASP.NET Core, it all goes down to the Use method in IApplicationBuilder. Lots of API-specific methods rely on it to add their own middleware.

For the time being, we’ll make use of the IMiddleware interface that comes with ASP.NET Core. It provides a simple contract that has no dependencies other than the common HTTP abstractions.

One common request is the ability to load and inject middleware components dynamically into the pipeline. Let’s see how we can

Managed Extensibility Framework

.NET Core has Managed Extensibility Framework (MEF), and I previously blogged about it. MEF offers an API that can be used to find and instantiate plugins from assemblies, which makes it an interesting candidate for the discovery and instantiation of such middleware components.

Image result for managed extensibility frameworkWe’ll use the System.Composition NuGet package. As in my previous post, we’ll iterate through all the assemblies in a given path (normally, the ASP.NET Core’s bin folder) and try to find all implementations of our target interface. After that we’ll register them all to the MEF configuration.

Implementation

Our target interface will be called IPlugin and it actually inherits from IMiddleware. If we so wish, we can add more members to it, for now, it really doesn’t matter:

public interface IPlugin : IMiddleware
{
}

The IMiddleware offers an InvokeAsync method that can be called asynchronously and takes the current context and a pointer to the next delegate (or middleware component).

I wrote the following extension method for IApplicationBuilder:

public static class ApplicationBuilderExtensions

{

public static IApplicationBuilder UsePlugins(this IApplicationBuilder app, string path = null)        {

     var conventions = new ConventionBuilder();

        conventions

           .ForTypesDerivedFrom<IPlugin>()

           .Export<IPlugin>()

           .Shared();

           path = path ?? AppContext.BaseDirectory;

            var configuration = new ContainerConfiguration()

            .WithAssembliesInPath(path, conventions);

            using (var container = configuration.CreateContainer())

            {

           var plugins = container

                .GetExports<IPlugin>()

                    .OrderBy(p => p.GetType().GetCustomAttributes<ExportMetadataAttribute>(true)

.SingleOrDefault(x => x.Name == “Order”)?.Value as IComparable ?? int.MaxValue); 

               foreach (var plugin in plugins)

                {

                    app.Use(async (ctx, next) =>

                    {

                    await plugin.InvokeAsync(ctx, null);

                        await next();

                    });

                }

          }

          return app;

    }

}

We define a convention that for each type found that implements IPlugin we register it as shared, meaning, as a singleton.

As you can see, if the path parameter is not supplied, it will default to AppContext.BaseDirectory.

We can add to the plugin/middleware implementation an ExportMetadataAttribute with an Order value to specify the order by which our plugins will be loaded, more on this in a moment.

The WithAssembliesInPath extension method comes from my previous post but I’ll add it here for your convenience:

public static class ContainerConfigurationExtensions
{     public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)     {      return WithAssembliesInPath(configuration, path, null, searchOption);     }     public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, AttributedModelProvider conventions, SearchOption searchOption = SearchOption.TopDirectoryOnly)     {         var assemblyFiles = Directory          .GetFiles(path, "*.dll", searchOption);         var assemblies = assemblyFiles             .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath);         configuration = configuration.WithAssemblies(assemblies, conventions);         return configuration;     }
}

If you want to search all assemblies in nested directories, you need to pass SearchOption.AllDirectories as the searchOption parameter, but this, of course, will have a performance penalty if you have a deep directory structure.

Putting it All Together

So, let’s write a few classes that implement the IPlugin interface and therefore are suitable to be used as middleware components:

[Export(typeof(IPlugin))] [ExportMetadata(“Order”, 1)] public class MyPlugin1 : IPlugin {     public async Task InvokeAsync(HttpContext context, RequestDelegate next)     {         //do something here

//this is needed because this can be the last middleware in the pipeline (next = null)         if (next != null)         {             await next(context);         }

//do something here     } }

Notice how we applied an ExportMetadataAttribute to the class with an Order value; this is not needed and if not supplied, it will default to the highest integer (int.MaxValue), which means it will load after all other plugins. These classes need to be public and have a public parameterless constructor. You can retrieve any registered services from the HttpContext’s RequestServices property.

Now, all we need to do is add a couple of assemblies to the web application’s bin path (or some other path that is passed to UsePlugins) and call this extension method inside Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{

//rest goes here

app.UsePlugins(/*path: “some path”*/);

//rest goes here

}

And here you have it: ASP.NET Core will find middleware from any assemblies that it can find on the given path.

Hope you find this useful! Winking smile

Performance in .NET – Part 2

Introduction

This is the second in a series of posts about performance in the .NET ecosystem. On the first post, that you can find here, I talked about object instantiation. This time, it’s object cloning.

Object Cloning

You should be aware that there are two types of cloning:

  • Deep cloning: clones the root object and each reference its properties points to
  • Shallow cloning: clones the root object but each reference any of its properties points to is kept, that is, is also pointed to, not cloned

Microsoft defines one interface, ICloneable, which is implemented by a couple of classes, but doesn’t really say much about the type of cloning that it does. In fact, Microsoft actually advises against using it.

Sometimes we definitely need to make a copy of an existing object. This includes creating a new instance and then populating it with the values (or copies of) for the properties of the initial class. We have a few options:

  • Using the built-in MemberwiseClone method
  • Implementing our own cloning strategy
  • Using an object-to-object mapper
  • Serializing and deserializing

Memberwise Shallow Clone

The Object class defines a MemberwiseClone method that the documentation describes as doing a shallow copy of the current object. Because this is defined for Object, all classes inherit it, and it will make a copy of all fields declared along the class hierarchy. But, alas, being generic also means that it is not particularly suited for any concrete scenario. It uses it uses FormatterServices.GetUninitializedObject to create a “blank” instance of your class and then reflection to iterate through all of the instance fields of your class and makes a bitwise copy of them. Because of the reflection part, it’s probably not the fastest solution.

Custom Clone

Here you need to decide if you’re going for a shallow or a deep strategy, and depending on that, things can be more or less complicated. In general, a shallow copy is faster and simpler to implement as we know exactly what properties to copy, and you can even go for a shallow or a deep copy. An option is to use an object mapper.

Using a Mapper

Using a mapper such as Automapper can prove very useful as it can do lots of things out-of-the-box for you and still leave you space to handle any more complex situations. There are many out there, but Automapper is probably the most popular but there are alternatives:

So, the idea is, you construct the target instance (the copy) yourself and then you use the mapper to copy from the current instance into it. A decent mapper can use conventions to copy without requiring any configuration, but it will still require some reflection magic.

Serializing and Deserializing

This one, like using a mapper, also requires a third-party library. There are plenty out there, even included in the .NET framework, that can do this. This may seem like an overkill if you’re just trying to get a clone of your current object, but it works, and it is usually one of the easiest ways to get a deep copy. This is usually used for transmitting an object’s state over the wire, in any format that can be binary or text-based, and it can go back as well, translating this state back into a class. Usually also not the fastest approach, especially for complex object graphs.

Conclusion

Performance-wise, you’re probably better off by rolling out your cloning method, which will probably be unique for each class. This avoids reflection and serialization (which also uses reflection). Just make it clear to everyone that you’re implementing a shallow or a deep copy.