## High Performance C#

* * *

C# is full of syntactic sugars... lambdas, linq, foreach, properties, actions, events, async, await.
                    These features make the language fun and fast to use, but, carry with it the hidden cost of garbage.

> 
>                     Garbage consists of transient objects located on the heap memory which have no references
>                     into user code. Garbage can induce application slowdowns as garbage collection needs to run to release these expired references.
>                 

* * *

### 
                    Do Use Structs

```

    // 0 garbage
    public struct EntityHealthData
    {
        public int Health;
    }
```

Structs (value types) are a must for any high end software. By living on the
                    stack memory they are easier to access for the CPU, especially when used in
                    lists or arrays.

* * *

### 
                    Don't Pass Structs As Objects

```

    void MyMethod(object value);

    void Start()
    {
        bool myStruct = true;
        //24 bytes of garbage
        MyMethod(myStruct);
    }
```

This is a common problem found in framework code that aims to be type agnostic. When we call *MyMethod*
                    We wrap our struct into a object for consumption by *MyMethod* causing a heap allocation of about 24 bytes.
                    This process is called *boxing*.

* * *

### 
                    Don't Cast Structs As Interfaces

```

    public Bullet : INetData
    {
        public int Damage;
    }

    //24 bytes of garbage
    void Send(INetData data);
```

Interfaces are heaped object, so our value type is once again boxed into an object.

* * *

### 
                    Do Use Generic Covariance

```

    public Bullet : INetData
    {
        public int Damage;
    }

    //0 bytes of garbage
    void Send<T>(T data) where T : INetData;
```

In the above example, calling send produces *no garbage*.

Generic methods are the correct way to make a type agnostic method which consumes value types. When compiled, a version of
                    this method is generated *for each type*, so no boxing is required.

* * *

### 
                    Don't use excessive events

```

    public event Action OnRaiseChange;
    
    public void AddListener()
    {
        //24 bytes of garbage
        OnRaiseChange += Handle;
    }
    public void Handle()
    {
        // Do Something!
    }
```

When we use the += operator, we add our *Handle*
                    delegate to the event list. Internally this calls *Delegate.Combine* which requires casting
                    the delegate into an *Action* and combining it with the previous Action delegate. This process
                    generates *208 bytes* of garbage per call.

* * *

### 
                    Don't Iterate Through IEnumerables

```

    public IEnumerable<T> Players;
    
    public void Start()
    {
        foreach(var player in Players)
        {
            //24 bytes of garbage
        }
    }
```

When we access an IEnumerable a *Enumerator* is created.
                    Enumerators are structs, but because it is accessed through the
                    IEnumerable interface, we cause our struct to get boxed.

Additionally, I recommend always casting a IEnumerable to a concrete
                    type. IEnumerables are *expressions* and is thus have lazy evaluation.
                    In other words whenever we access the Enumerable the data source is reevaluate and we could get desynced data.

* * *

### Do Preallocate Arrays and Lists

```

    var BadPlayers = new List<TPlayer>();
    var GoodPlayers = new List<TPlayer>(16);
    var BestPlayers = new TPlayer[16];

    BadPlayers.Add(myPlayer); // 78 bytes of garbage
    GoodPlayers.Add(myPlayer); // 0 bytes of garbage
```

Each time a list needs to resize its internal array it generates 78 bytes of garbage.
                    Please initialize them with a size, or better yet use an array.

* * *

### Don't Use System.Equals

```

    public bool BetterEqual(int a, int b)
    {
        //24 bytes of garbage
        return System.Equals(a, b);
    }
```

Many of the older .Net 2.0 System methods box structs as objects, generating garbage.

This can be especially frustrating when using Enums which idiomatically
                    are value types, but when used with the system helper classes are immediately boxed.

As a workaround use the generic EqualityComparer&lt;T&gt; class.

* * *

### Don't abuse anonymous methods

```
   
        //24 bytes of garbage
        await networkService.Post(request, response => 
        {
            //handle here
        });
```

When we declare an anonymous method using the fat arrow operator, we are instantiating a
                    heaped object to keep state and instantiating it.

A better solution is to write a proper method for handling our response.

* * *

### Don't Spam Tasks

```
   
    foreach(var actionData in actionQueue)
    {
        await networkService.Post(actionData);
    }
```

As a Task enthusiast this one is hard for me. When I compare my options of how
                    to handle asynchronous transactions Tasks are great. They are easy to read, and consolidate code.

Internally they are a Synchronization Context with a callback. The Synchronization
                    Context is the killer here. When writing my networking library I originally used tasks
                    and discovered I wasted **30%** of my cpu throughput on context switching. This was
                    compared against just using a dedicated thread and a circular queue.

For those not familiar, context switching is the system returning scope back to the
                    calling thread. So if you start a task on thread A, it runs on thread B, it should return
                    on thread A.

As a workaround use the *ConfigureAwait* extension method. That said, for games especially,
                    having an concurrent or circular queue that runs synchronously is a best practice.

```

    foreach(var actionData in actionQueue)
    {
        await networkService.Post(actionData).ConfigureAwait(false);
    }
```

* * *

### Conclusion

Some of these suggestions can be considered *Micro Optimizations*,
                    so please use your best judgment when implementing. These are best saved for
                    Framework and Networking code. For general user code, please favor readability
                    and maintainability.

* * *

<small>All views are my own, and I do not represent any employer. All ownership of attached open source code is waved.</small>