Back to directory
bcronce avatar
bcronce / BoringHelpers

BoringHelpers

General use library

4

Stars

0

Forks

0

Watchers

MIT

License

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

Releases

v0.2.0.0

Pre-release

Jan 4, 2020

Refactor Collections.Empty

Download .zip

Minor breaking changes to Collections.Empty. Code should compile without changes, but the returned types are no longer the interfaces, but classes that implement the interfaces. Nuget

v0.1.3.0

Pre-release

Oct 6, 2019

SimpleMetadata<T>

Download .zip

SimpleMetadata<T> is a new abstract class to make it easier to add type safety to metadata. Nuget

v0.1.2.0

Pre-release

Aug 4, 2019

Fixed KeyThrowingDictionary

Download .zip

KeyThrowingDictionary effectively did not work, but it passed the tests because .Net Core includes the key in the message. Had to setup the unit tests to multi-target Core and Framework. For some reas...

v0.1.1.0

Pre-release

Jul 17, 2019

KeyThrowingDictionary

Download .zip

Added new KeyThrowingDictionary class. Nuget

v0.1.0.1

Pre-release

Jul 11, 2019

MultiTarget framework

Download .zip

Same code base as v0.1.0 but targeting Standard1.3 and Framework4.6. No more screen full of dependencies when adding to a framework project. Hope I didn't mess anything up. Nuget