Skip to content

Tazmainiandevil/Useful.Extensions

Repository files navigation

Useful.Extensions

A group of useful extensions in C#, supporting .NET 6.0 and .NET 7.0

NuGet version

I found myself creating useful extensions over and over as I moved along my career path and decided that they actually needed a home to be reusable and grow. They are not trade secrets or proprietary code they are just little bits of code that are useful.

Methods

Array Extensions

SafeGetElement - Gets an element from an array, without throwing an exception if the index is out of bounds.

Using just the index parameter (array location)

e.g.

var intArray = new[] { 2, 4, 8, 1, 7 };
var itemValue = intArray.SafeGetElement(2);

itemValue will be 8.

Using the array location and a default value to return if the element is not found

e.g.

var intArray = new[] { 2, 4, 8, 1, 7 };
var itemValue = intArray.SafeGetElement(20, 1);

itemValue will be 1, as the array does not contain 20 elements.

Using the array location, default value and a function to apply to the element value

e.g.

var intArray = new[] { 2, 4, 8, 1, 7 };
var itemValue = intArray.SafeGetElement(1, 1, (s) => s * 2);

itemValue will be 8, as the element at location 1, is 4, which is then multiplied by 2.

The test project has more examples using strings and classes.

Character Extensions

EqualTo - A simple comparison of characters including an option to compare by the case (default is to ignore case)

e.g.

'c'.EqualTo('C');

or

'c'.EqualTo('C', StringComparison.Ordinal);

String Extensions

ContainsValue (same as HasValue) - Looks for a specified value inside a string including an option to compare by the case (default is to ignore case)

e.g.

"XYZ".ContainsValue("x");

or

"XYZ".ContainsValue("x", StringComparison.Ordinal);

HasValue - Looks for a specified value inside a string including an option to compare by the case (default is to ignore case)

e.g.

"XYZ".HasValue("x");

or

"XYZ".HasValue("x", StringComparison.Ordinal);

EqualsIgnoreCase - A wrapper around Equals to always be a case-insensitive check. The check is also safe and returns false if the string is null or empty.

e.g.

"XYZ".EqualsIgnoreCase("xyz");
string value = null;
value.EqualsIgnoreCase(null);

both examples return true

SubstringOrEmpty - A safe version of substring that returns an empty string if the substring is completely out of range or the value found if the length is out of range

e.g.

"Hello World".SubstringOrEmpty(12, 10);

returns ""

"Hello World".SubstringOrEmpty(9, 10);

returns "ld"

SubstringAfterValue - A substring that returns the remaining string after a given string or character ignoring the case by default

e.g.

"Hello World".SubstringAfterValue("Hello ");

returns "World"

"Hello World".SubstringAfterValue('W');

returns "orld"

Case Sensitive substring

"Hello world World".SubstringAfterValue('W', StringComparison.Ordinal);

returns "orld"

"Hello world World".SubstringAfterValue("world", StringComparison.Ordinal);

returns " World"

SubstringAfterLastValue - A substring that returns the remaining string after the last occurrence of a given character or string ignoring case by default

e.g.

"Hello World [email protected]".SubstringAfterLastValue("Hello");

returns "@world.com"

"Hello World [email protected]".SubstringAfterLastValue('W');

returns "orld.com"

Case Sensitive substring

"Hello world World".SubstringAfterLastValue('W', StringComparison.Ordinal);

returns "orld"

"Hello world World".SubstringAfterLastValue("world", StringComparison.Ordinal);

returns " World"

SubstringBeforeValue - A substring that returns the string before a given string or character ignoring the case by default

e.g.

"Hello World".SubstringBeforeValue(" World");

returns "Hello"

"Hello World".SubstringBeforeValue('W');

returns "Hello "

Case Sensitive substring

"Hello world World".SubstringBeforeValue(" World", StringComparison.Ordinal);

returns "Hello world"

"Hello world World".SubstringBeforeValue('W', StringComparison.Ordinal);

returns "Hello world "

SubstringBeforeLastValue - A substring that returns the string before the last occurrence of a given string or character ignoring the case by default

e.g.

"Hello World World".SubstringBeforeLastValue(" world");

returns "Hello World"

"Hello World World".SubstringBeforeLastValue('w');

returns ""Hello World "

Case Sensitive substring

"Hello World world".SubstringBeforeLastValue(" World", StringComparison.Ordinal);

returns "Hello"

"Hello World world".SubstringBeforeLastValue('W', StringComparison.Ordinal);

returns ""Hello "

SafeTrim - A safe version of trim that does not throw an exception if the string is null

e.g.

(null as string).SafeTrim();

returns null

SafeStartsWith - A safe version of starts with that does not throw an exception if the string is null

e.g.

(null as string).SafeStartsWith("Find");

returns false

SafeEndsWith - A safe version of ends with that does not throw an exception if the string is null

e.g.

(null as string).SafeEndsWith("Find");

returns false

IsBase64 - A check to see if a string has been base64 encoded e.g.

var value = Convert.ToBase64String(Encoding.UTF8.GetBytes("some value"), Base64FormattingOptions.None);
value.IsBase64();

returns true

or

"some value".IsBase64();

returns false

IsAllNumbers - Determine if the whole string value contains only number characters

e.g.

"1235456".IsAllNumbers();

returns true

e.g.

"1235456ABc".IsAllNumbers();

returns false

IsAllAlpha - Determine if the whole string value contains only alpha characters

e.g.

"ABCDE".IsAllAlpha();

returns true

e.g.

"ABCDE123$".IsAllAlpha();

returns false

IsAllAlphaOrNumbers - Determine if the whole string value contains only alpha or number characters

e.g.

"1A235456c".IsAllAlphaOrNumbers();

returns true

e.g.

"1A235456c%%".IsAllAlphaOrNumbers();

returns false

Dictionary Extensions

ValueOrDefault - Get the value from a dictionary or return the default for the value type (the default value can be specified if needed)

e.g.

new Dictionary<string, int> { { "some text", 1 }, { "more text", 2 } }.ValueOrDefault("value", 99);

returns 99

new Dictionary<string, int> { { "some text", 1 }, { "more text", 2 } }.ValueOrDefault("some text");

returns 1

TryGetValueOrDefault - Same as ValueOrDefault only uses the dictionary method TryGetValue which depending on dictionary size can be more performant

e.g.

new Dictionary<string, int> { { "some text", 1 }, { "more text", 2 } }.TryGetValueOrDefault("value", 99);

returns 99

new Dictionary<string, int> { { "some text", 1 }, { "more text", 2 } }.TryGetValueOrDefault("some text");

returns 1

Enumerable Extensions

Partition - Splits an IEnumerable collection into multiple collections based on size

e.g.

var items = new List<int> { 0, 1, 2, 3, 4, 5, 6 };`
var result = items.Partition(4);

returns an IEnumerable<IEnumerable<int>> that contains 2 lists one with 0, 1, 2, 3 one with 4, 5, 6

Page - Get a part or page of data from an IEnumerable

e.g.

var items = new List<int> { 0, 1, 2, 3, 4, 5, 6 };`
items.Page(0, 2);

returns a list with 0 and 1 in

IsNullOrEmpty - Performs a check on a collection for null or empty

e.g.

List<int> list = null;
if(list.IsNullOrEmpty())
{
  // Perform logic here
}

or

var list = new List<string> { "somevalue" };
if(!list.IsNullOrEmpty())
{
  // Perform logic here
}

IsValueInList - Checks for a value that exists in the list

e.g.

var list = new[] { "One", "Two", "Three", "Four" };
if(list.IsValueInList("five"))
{
  // Perform logic here
}

or

var list = new[] { 1, 2, 3, 4 };
if(list.IsValueInList(3))
{
  // Perform logic here
}

Join - A fluent version of the classic string.Join() methods

If you have an array/list of strings and you want to output them as a comma-delimited string, then the code you would have to write would look like this:

var items = new string[] { "Me", "You", "Them", "Us" };
var itemsAsString = string.Join(", ", items);

The output would be:

Me, You, Them, Us

Wouldn't it be nice to use a fluent style, like this:

var items = new string[] { "Me", "You", "Them", "Us" };
var itemsAsString = items.Join(", ");

Or this:

var items = new List<string> { "Me", "You", "Them", "Us" };
var itemsAsString = items.Join(", ");

Well, now you can.

The output of both of those examples would be:

Me, You, Them, Us

The same as if you used the original.

It is possible to use this extension on other types as there is a generic extension that will accept an IEnumerable<T>. However, the class must have an overridden ToString() method, otherwise, it will return the class name.

As an example, this test class doesn't override the ToString() method, so when we call it like this:

var items = new List<TestClass> { "Me", "You", "Them", "Us" };
var itemsAsString = items.Join(", ");

The output is like this:

Useful.Extensions.Tests.TestClasses.TestClass

Not very useful, is it? So, ensure the class in your list has an override for the ToString() method before using this extension.

List Extensions

Combine - Combine multiple lists together

e.g.

var list = new List<string> { "Hello" };
var additionalList = new List<string> { "World" };
var anotherList = new List<string> { "Bye" };

list.Combine(additionalList, anotherList);

Results in a list containing "Hello", "World", "Bye"

Add Many - Add multiple items to a list

e.g.

var items = new List<string> { "Hello", "World" };

items.AddMany("Another", "Day");

Results in a list containing "Hello", "World", "Another", "Day"

Nullable Extensions

ToStringOrEmpty - String representation of a nullable value or an empty string if the nullable has no value

IsEqual - Checks if the nullable value is equal to another value

e.g.

int? value = null;
value.IsEqual(14);

returns false

IsNullOrDefault - Check if the value is null or the default value

e.g.

int? value = 0;
value.IsNullOrDefault();

returns true as the default for an int is 0

bool? value = true;
value.IsNullOrDefault();

returns false

ValueOrDefault - Retrieves the value of the nullable or the default of the type if there is not a value or specified default value

e.g.

long? value = 123456;
value.ValueOrDefault();

returns 123456

int? value = null;
value.ValueOrDefault(-1);

returns -1 as that was the default specified

Enum Flag Extensions

[Flags]
public enum TestEnum : short
{
    None = 0,
    Item1 = 1,
    Item2 = 2,
    Item3 = 4,
    Item4 = 8,
    Item5 = 16,
    Item6 = 32
}

Contains - Returns a boolean to denote if the specified flag has been set

var testValue = TestEnum.Item1;

var result = testValue.Contains(TestEnum.Item1);

result would be true

HasAnyOf - Returns a boolean to denote if any of the specified flags have been set

var testValue = TestEnum.Item1 | TestEnum.Item5;

var result = testValue.HasAnyOf(TestEnum.Item5);

result would be true

HasAllOf - Returns a boolean to denote if all of the specified flags have been set

var testValue = TestEnum.Item1 | TestEnum.Item5 | TestEnum.Item2;

var result = testValue.HasAllOf(TestEnum.Item5, TestEnum.Item2);

result would be true

Set - Set flags on a given enum

 var value = TestEnum.None;
 var result = value.Set(TestEnum.Item2, TestEnum.Item6);

 result.All(TestEnum.Item2, TestEnum.Item6)

result would be true

UnSet - UnSet flags on a give enum

 var value = TestEnum.None;
 var result = value.UnSet(TestEnum.Item2);

 result.Contains(TestEnum.Item2);

return would be false

Enum Extensions

public enum TestEnumDescription
{
    [Description("none")]
    None = 0,
    [Description("one")]
    Item1 = 1,
    [Description("two")]
    Item2 = 2
}

GetDescription - Gets the description value from an enum

var item = TestEnumNoDescription.Item1;
var description = item.GetDescription();

return value would be "one"

Date Time Extensions

ShouldBeWithinRangeOf - Determines that a DateTime is close to an expected date. Has an optional parameter of an int. This represents the variation we can accept in seconds.

e.g.

var dateToCheck = new DateTime(2017, 01, 01, 12, 30, 00);
var expectedDateToCheck = new DateTime(2017, 01, 01, 12, 30, 05);

dateToCheck.ShouldBeWithinRangeOf(expectedDateToCheck);

returns true, as the date and time we are checking are within five seconds of the expected date and time.

var dateToCheck = new DateTime(2017, 01, 01, 12, 30, 00);
var expectedDateToCheck = new DateTime(2017, 01, 01, 12, 30, 11);

dateToCheck.ShouldBeWithinRangeOf(expectedDateToCheck);

returns false, as the date and time we are checking are over the default ten seconds of the expected date and time.

var dateToCheck = new DateTime(2017, 01, 01, 12, 30, 00);
var expectedDateToCheck = new DateTime(2017, 01, 01, 12, 30, 19);

dateToCheck.ShouldBeWithinRangeOf(expectedDateToCheck, 20);

returns true, as the date and time we are checking are within nineteen seconds of the expected date and time. This is using the optional parameter where we can set the seconds of variation.

Between - Determines if the DateTime is between a specified start and end time. Has an optional parameter of a bool. This defaults to false and doesn't include the specific start time or end time.

e.g.

var dateToCheck = new DateTime(2017, 01, 01, 12, 30, 00);
var startOfRange = new DateTime(2016, 12, 15, 12, 30, 00);
var endOfRange = new DateTime(2017, 01, 02, 23, 59, 59);

dateToCheck.Between(startOfRange, endOfRange);

returns true, as the date and time being checked are within the ranges supplied.

var dateToCheck = new DateTime(2017, 01, 02, 12, 30, 00);
var startOfRange = new DateTime(2016, 12, 15, 12, 30, 00);
var endOfRange = new DateTime(2017, 01, 02, 12, 30, 00);

dateToCheck.Between(startOfRange, endOfRange, true);

returns true, as the date and time being checked are within the ranges supplied, and as the inclusive parameter is true, we are going right up to the end range limit.

GetAge - Get the age from a given date representing the Date of Birth and now or a given date

e.g.

var dob = new DateTime(2003, 07, 04);

var ageToday = dob.GetAge();

ageToday (ran on 05/01/2020) would return 16. If supplying the date then it would return the same using the syntax below

e.g.

var dob = new DateTime(2003, 07, 04);

var ageToday = dob.GetAge(new DateTime(2020, 01, 05));

System Time Helpers

Allow date/time now entries to be testable. This was inspired by Oren Eini https://ayende.com/blog/3408/dealing-with-time-in-tests.

e.g.

var now = SystemTime.Now();

var utc = SystemTime.UtcNow();

To set up a time in the unit tests so that when System.Now() or System.UtcNow() is called it will be a specified date/time

SystemTime.Now = () => new DateTime(2000, 1, 1, 10, 10, 47);

SystemTime.UtcNow = () => new DateTime(2000, 1, 1, 9, 10, 47);

Object Helpers

Clone - An implementation of a deep clone using serialization

The next set are helper functions rather than extensions

GetValueFromAnonymousType - Get values from dynamic objects by property name

e.g.

var anon = new { Text = "Hello" };`
ObjectExtensions.GetValueFromAnonymousType<string>(anon, "Text");

returns "Hello"

GetValueFromAnonymousTypeOrDefault - As with GetValueFromAnonymousType but returns a default value for the type if not found e.g.

var anon = new { Text = "Hello" };`
ObjectExtensions.GetValueFromAnonymousTypeOrDefault<string>(anon, "Value");

returns null

IsPropertyInAnonymousType - Checks to see if there is a property of a given name inside a dynamic object e.g.

var anon = new { Text = "Hello" };`
ObjectExtensions.IsPropertyInAnonymousType(anon, "Value");

returns false