Skip to content

bcronce/BoringHelpers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BoringHelpers

Licence Build Status NuGet CodeFactor

General use library inspired by common patterns seen in production code.

The goal of this project is to help make code easier to read and more efficient. Secondary to that is to learn and practice CI, high coverage unit testing, and otherwise polishing code to a degree that one many times cannot at work.

I love myself a good philosophical debate about code. Feel free to provide constructive criticism.

Why Boring

It may not be exciting code, but that's why I am excited about it.

Over these many decades roaming life, I have come to believe that the quality of a product is not defined by how good it typically is, but how bad it can be. What can go wrong will go wrong, at the most inopportune time, and in the worst way possible. Boring code shouldn't supprise you.

Collections

Light weight collections that implement common interfaces.

Empty

It is common to have to pass an empty collection. While there exists some common ones in the BCL like Array.Empty or Enumerable.Empty, they are spread around, sub-optimal, and there is not an Empty for all of the common interfaces.

Empty collection are special in that many aspects of them can be stateless. For example, there is no reason to allocate a new enumerator when iterating them.

Individual

In my expereience, it is very common to have a collection of a single element. While I wanted to name it Single, that conflicts with a synonym with Float.

I can't tell you how many times I've seen new Dictionary {{ key, value }}. Not only does the Dictionary collection need to make an Array, it also needs to hash the key. When working with a single collection, you can just hold the single KeyValue and skip hashing on both creation and lookups. Similar optimizations can be made to other collections when you only have a single element.

Also in my expereience, many of these single element collections tend to be allocated in hot paths. Sizable reductions in GC and CPU time can be had while making the code easier to read. Win-win-win.

KeyThrowingDictionary

Admit it. You've had it where some quickly slapped together project throws a KeyNotFound exception and you get driven crazy that you have no idea what key caused the exception.

I was originally going to create a new class that wrapped a Dictionary, but that would cause more code paths to have to be tested and meant two objects would be created. I played around with just inheriting from Dictionary and it worked well. It allowed for a minimal class that only changed the few methods that I cared to change with the additional benefit that this can be downcasted into a Dictionary for those times someone didn't give an IDictionary signature.

Types

For now, it's just SimpleMetadata

SimpleMetadata

Some times you have coode that looks like

void SomeMethod(Guid id, string typeId)

And it's just Guid this and string that. So you want to make proper types so you code can look like

void SomeMethod(EntityId id, EntityTypeId typeId)

But can be a lot of yak shaving if you want to have something like Dictionary<EntityId, value>. You can instead do something like

public class EntityId : SimpleMetadata<Guid>
{
    public EntityId(string value)
        : base(value) { }
}

Now you have EntityId without all of the setup.

And if you have some special situation, you can easily override the behavior, like case insensitive.

public abstract class EntityTypeId : SimpleMetadata<string>
{
    protected override IEqualityComparer<string> EqualityComparer { get { return StringComparer.OrdinalIgnoreCase; } }
    protected override IComparer<string> Comparer { get { return StringComparer.OrdinalIgnoreCase; } }

    protected EntityTypeId(string value)
        : base(value) { }
}

And since case insensetive is such a common thing, I already included a class CaseInsensitiveMetadata that is implemented like the above EntityTypeId example.

And yes, == is overriden. So you get this out of the box.

public class EntityId : SimpleMetadata<Guid>
{
    public EntityId(string value)
        : base(value) { }
}

Guid value = Guid.NewGuid();
EntityId id = new EntityId(value);
EntityId id2 = new EntityId(value);

Assert.True(id == id2);
Assert.True(id == value);