Skip to content

rmandvikar/csharp-extensions

Repository files navigation

csharp-extensions

A collection of utility C# extension methods.

main: Build Status dev: Build Status

nuget:

Install-Package rm.Extensions 

NuGet version (rm.Extensions)

string extensions:

var s = ""; if (s.IsNullOrEmpty()) { /**/ } if (s.IsNullOrWhiteSpace()) { /**/ }
// some string that could be null/empty/whitespace string s = null; // or "value" string text = "default"; if (!s.IsNullOrWhiteSpace()) text = s.Trim(); // fluent code by avoiding comparison string text = s.OrEmpty().Trim(); // "" when s is null/empty/whitespace string text = s.Or("default").Trim(); // "default" when s is null/empty/whitespace // or using null-conditional and null-coalesce operators string text = s.NullIfEmpty()?.Trim() ?? "" string text = s.NullIfWhiteSpace()?.Trim() ?? "default"
// html-en/decode, url-en/decode string s = ""; string htmlencoded = s.HtmlEncode(); string htmldecoded = s.HtmlDecode(); string urlencoded = s.UrlEncode(); string urldecoded = s.UrlDecode();
// "".Format() instead of string.Format() "{0} is a {1}".Format("this", "test"); // parameter index is optional "{} is a {}".Format("this", "test"); "{} is a {1}".Format("this", "test"); // mixing is ok // parameter meta is allowed "The name is {0}. {first} {last}.".Format(lastName, firstName, lastName); // adding arg meta is ok "The name is {last}. {first} {last}.".Format(lastName, firstName); // bit intelligent about repeating arg meta
// bool try-parse string with default value bool b = "".ToBool(defaultValue: true); // b: true
// munge a password, up to two chars string[] munged = "pass".Munge().ToArray(); // munged: { "pa$$", "pa55", "p@ss", "p@$$", "p@55" } string[] munged = "ai".Munge().ToArray(); // munged: { "a1", "a!", "@i", "@1", "@!" } string[] munged = "pw".Munge().ToArray(); // munged: { "puu", "p2u" } // unmunge a password string[] unmunged = "h@x0r".Unmunge().ToArray(); // unmunged: { "haxor" } string[] unmunged = "puu".Unmunge().ToArray(); string[] unmunged = "p2u".Unmunge().ToArray(); // unmunged: { "pw" }
// scrabble characters of word (like the game) var word = "on"; var scrabbled = word.Scrabble(); // scrabbled: { "o", "on", "n", "no" }
// parse a string in UTC format as DateTime DateTime date = "2013-04-01T03:42:14-04:00".ParseAsUtc(); // date: 4/1/2013 7:42:14 AM, Kind: Utc
// convert a string to title case string result = "war and peace".ToTitleCase(); // result: "War And Peace"
// split a csv string string[] result = "a,b;c|d".SplitCsv().ToArray(); // result: [ "a", "b", "c", "d" ]
// substring from start string result = "this is a test".SubstringFromStart(4); // result: "this"
// substring till end string result = "this is a test".SubstringTillEnd(4); // result: "test"
// substring by specifying start index and end index string result = "this".SubstringByIndex(1, 3); // result: "hi"
// parse timespan duration string TimeSpan duration = "7d".ParseDuration(); // duration: TimeSpan.FromDays(7) TimeSpan duration = "1h2m3s".ParseDuration(); // duration: TimeSpan.FromHours(1) + TimeSpan.FromMinutes(2) + TimeSpan.FromSeconds(3) TimeSpan duration = "-7d".ParseDuration(); // duration: -TimeSpan.FromDays(7) TimeSpan duration = "1y1mo1wk1d1h1m1s1ms1us".ParseDuration(); TimeSpan duration = "1y 1mo 1wk 1d 1h 1m 1s 1ms 1us".ParseDuration();

ThrowIf extensions:

public void SomeMethod(object obj1, object obj2) { // throws ArgumentNullException if object is null obj1.ThrowIfArgumentNull("obj1"); obj2.ThrowIfArgumentNull("obj2"); // OR  new[] { obj1, obj2 }.ThrowIfAnyArgumentNull(); // ... object obj = DoSomething(); // throws NullReferenceException if object is null obj.ThrowIfNull("obj"); // OR  new[] { obj1, obj2 }.ThrowIfAnyNull(); }
public void SomeMethod(string s1, string s2) { // throws ArgumentNullException or EmptyException if string is null or empty s1.ThrowIfNullOrEmptyArgument("s1"); // or s1.ThrowIfNullOrWhiteSpaceArgument("s1") s2.ThrowIfNullOrEmptyArgument("s2"); // OR  new[] { s1, s2 }.ThrowIfNullOrEmptyArgument(); // ... string s = DoSomething(); // throws NullReferenceException or EmptyException if string is null or empty. s.ThrowIfNullOrEmpty("s"); // or s1.ThrowIfNullOrWhiteSpace("s") }

DateTime extensions:

// gives date in UTC format string string dateUtc = date.ToUtcFormatString(); // dateUtc: "1994-11-05T13:15:30.000Z"
// gives min date that can be inserted in sql database without exception (SqlDateTime.MinValue) DateTime date = new DateTime().ToSqlDateTimeMinUtc(); // date: 1/1/1753 12:00:00 AM
// date read from db or parsed from string has its Kind as Unspecified. // specifying its kind as UTC is needed if date is expected to be UTC. // ToUniversalTime() assumes that the kind is local while converting it and is undesirable. DateTime date = DateTime.Parse("4/1/2014 12:00:00 AM").AsUtcKind(); // date: 4/1/2014 12:00:00 AM, Kind: Utc

IEnumerable extensions:

// creates chunks of given collection of specified size IEnumerable<IEnumerable<int>> chunks = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }.Chunk(3); // chunks: { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10 } }
// if a collection is null or empty var collection = new[] { 1, 2 }; if (collection.IsNullOrEmpty()) { /**/ }
// split a collection into n parts var collection = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; IEnumerable<IEnumerable<int>> splits = collection.Split(3); // splits: { { 1, 4, 7, 10 }, { 2, 5, 8 }, { 3, 6, 9 } }
// if a collection is sorted var collection1 = new[] { 1, 2, 3, 4 }; bool isSorted1 = collection1.IsSorted(); var collection2 = new[] { 7, 5, 3 }; bool isSorted2 = collection2.IsSorted(); // isSorted1, isSorted2: true
// Double(), DoubleOrDefault() as Single(), SingleOrDefault() IEnumerable<int> doubleitems = new[] { 1, 2 }.Double(); // doubleitems: { 1, 2 } IEnumerable<int> doubleitems = new[] { 1, 2, 3 }.Double(x => x > 1); // doubleitems: { 2, 3 } IEnumerable<int> doubleordefaultitems = new int[0].DoubleOrDefault(); // doubleordefaultitems: null IEnumerable<int> doubleordefaultitems = new[] { 1, 2, 3 }.DoubleOrDefault(x => x > 1); // doubleordefaultitems: { 2, 3 } // throws InvalidOperationException new[] { 1 }.Double(); new[] { 1 }.Double(x => x > 0); new[] { 1 }.DoubleOrDefault(); new[] { 1 }.DoubleOrDefault(x => x > 0);
// shuffle collection in O(n) time (Fisher-Yates shuffle, revised by Knuth) var shuffled = new[] { 0, 1, 2, 3 }.Shuffle(); // shuffled: { 2, 3, 1, 0 }
// slice a collection as Python (http://docs.python.org/2/tutorial/introduction.html#strings) var a = new[] { 0, 1, 2, 3, 4 } var slice = a.Slice(step: 2); // slice: { 0, 2, 4 } a.Slice(start, end);// items start through end-1 a.Slice(start);// items start through the rest of the array a.Slice(0, end);// items from the beginning through end-1 a.Slice();// a copy of the whole array a.Slice(start, end, step);// start through not past end, by step a.Slice(-1);// last item in the array a.Slice(-2);// last two items in the array a.Slice(-3, -2);// third last item in the array a.Slice(0, -2);// everything except the last two items a.Slice(step: -1);// copy with array reversed // help a.Slice(end: 2)// 1st 2 a.Slice(2)// except 1st 2 a.Slice(-2)// last 2 a.Slice(0, -2)// except last 2 a.Slice(1, 1 + 1)// 2nd char a.Slice(-2, -2 + 1)// 2nd last char
// scrabble a list of words (like the game) var words = { "this", "test" }; var scrabbled = words.Scrabble(); // scrabbled: { "this", "thistest", "test", "testthis" }
// check an enumerable's count efficiently if (enumerable.Count() == 2) { ... } // inefficient for large enumerable if (enumerable.HasCount(2)) { ... } if (enumerable.HasCountOfAtLeast(2)) { ... } // count >= 2
// get permutations or combinations for particular r var result = new[] { 1, 2 }.Permutation(2); // result: { { 1, 2 }, { 2, 1 } } var result = new[] { 1, 2 }.Combination(2); // result: { { 1, 2 } }
// if a collection is empty instead of !collection.Any() var collection = new[] { 1, 2 }; if (collection.IsEmpty()) { /**/ }
// get top n or bottom n efficiently (using min/max-heap) IEnumerable<int> top_n = { 2, 3, 1, 4, 5 }.Top(3); IEnumerable<int> bottom_n = { 2, 3, 1, 4, 5 }.Bottom(3); // top_n: { 3, 5, 4 } // bottom_n: { 3, 1, 2 } // get top n or bottom n from IEnumerable IEnumerable<Person> top_n = persons.Top(3); IEnumerable<Person> bottom_n = persons.Bottom(3); // get top n or bottom n by using a key selector or/and comparer IEnumerable<Person> oldest_3 = persons.Top(3, x => x.Age); IEnumerable<Person> youngest_3 = persons.Bottom(3, x => x.Age); IEnumerable<Person> oldest_3 = persons.Top(3, personByAgeComparer); IEnumerable<Person> youngest_3 = persons.Bottom(3, personByAgeComparer); IEnumerable<Person> oldest_3 = persons.Top(3, x => x.Age, ageComparer); IEnumerable<Person> youngest_3 = persons.Bottom(3, x => x.Age, ageComparer);
// source.Except(second, comparer) linqified instead of a full-blown class for comparer source.ExceptBy(second, x => x.Member); // same for source.Distinct(comparer) source.DistinctBy(x => x.Member); // same for source.OrderBy(keySelector, comparer) source.OrderBy(x => x.Property, (p1, p2) => p1.CompareTo(p2) // where p1, p2 are of same type as x.Property );
// source.OrEmpty() or source.EmptyIfDefault() to avoid a null check foreach (var item in source.OrEmpty()) { /**/ } foreach (var item in source.EmptyIfDefault()) { /**/ } // instead of if (source != null) { foreach (var item in source) { /**/ } }
// TrySingle() to get single without exception if (source.TrySingle(out singleT)) { ... }
// OneOrDefault() to get the only one element or default //	input	firstOrDefault	singleOrDefault	oneOrDefault //	{ 1, 2 }	1	throws	default //	{ 1 }	1	1	1 //	{ }	default	default	default var oneT = source.OneOrDefault();
// calls IEnumerable.Contains() bool result = value.In(source); bool result = value.In(source, comparer);

IList extensions:

// RemoveLast() to remove last item(s) in list list.RemoveLast(); list.RemoveLast(2);

Enum extensions:

enum Color { Red = 1, Green, Blue }; Color color = "Red".Parse<Color>(); // OR Color color; "Red".TryParse<Color>(out color); // color: Color.Red
enum Color { [Description("Red color")] Red = 1, Green, [Description("Blue color")] Blue } string redDesc = Color.Red.GetDescription(); string greenDesc = Color.Green.GetDescription(); // redDesc: "Red color" // greenDesc: "Green"
enum Color { Red = 1, Green, Blue }; Color color = "Red".GetEnumValue<Color>(); // color: Color.Red // enumValue.GetEnumName() is fastest of all // fastest, dictionary lookup after 1st call if (Color.Red.GetEnumName() == "Red") { /**/ } // slightly slow, dictionary lookup after 1st call if ("Red".GetEnumValue<Color>() == Color.Red) { /**/ } // slow, due to reflection if ("Red".Parse<Color>() == Color.Red) { /**/ } // slowest, due to reflection if (Color.Red.ToString() == "Red") { /**/ }
enum Color { [Description("Red color")] Red = 1, Green, [Description("Blue color")] Blue } IDictionary<string, string> colorsMap = EnumExtension.GetEnumNameToDescriptionMap<Color>(); // build a select list IEnumerable<ListItem> selectOptions = colorsMap .Select(x => new ListItem() { text: x.Value, value: x.Key }); // <select> // <option value="Red">Red color</option> // <option value="Green">Green</option> // <option value="Blue">Blue color</option> // </select>
enum Color { [Description("Red color")] Red = 1, Green, [Description("Blue color")] Blue } string redName = "Red color".GetEnumNameFromDescription<Color>() // redName: "Red"
bool hasValue = 0.IsDefined<Color>(); // hasValue: false bool hasValue = 1.IsDefined<Color>(); // hasValue: true
enum Color { [Description("Red color")] Red = 1, Green, [Description("Blue color")] Blue }
// compile error: cannot have int as enum values or hyphen sign in enum values enum Grade { Toddler, Pre-K, Kindergarten, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, College } // work-around: use Description attribute enum Grade { Toddler = 1, [Description("Pre-K")] PreK, Kindergarten, [Description("1")] One, [Description("2")] Two, [Description("3")] Three, [Description("4")] Four, [Description("5")] Five, [Description("6")] Six, [Description("7")] Seven, [Description("8")] Eight, [Description("9")] Nine, [Description("10")] Ten, [Description("11")] Eleven, [Description("12")] Twelve, College } // to sort gradesUnsorted, use GetEnumValueFromDescription<T>() and GetDescription<T>() methods string[] gradesUnsorted = new[] { "Pre-K", "1", "College", "2", "Toddler" }; Grade[] grades = gradesUnsorted .Select(x => x.GetEnumValueFromDescription<Grade>()).ToArray(); Array.Sort(grades); string[] gradesSorted = grades.Select(x => x.GetDescription()); // gradesSorted: { "Toddler", "Pre-K", "1", "2", "College" } 

NameValueCollection extensions:

// get query string for name-value collection NameValueCollection nvc = new NameValueCollection { {"k1,", "v1"}, {"k2", "v2"} }; string query = nvc.ToQueryString(); // OR nvc.ToQueryString(prefixQuestionMark: false); // query: "?k1%2C=v1&k2=v2" // OR "k1%2C=v1&k2=v2"

TimeSpan extensions:

// round timespan as ms, s, m, h, d, wk, mo, y. string round = TimeSpan.FromDays(10).Round(); // round: "1wk"
// n Days, Hours, Minutes, Seconds, Milliseconds, etc. TimeSpan ts = 10.Days();

Helper methods:

// swap two values or references Helper.Swap(ref a, ref b);

decimal extensions:

// truncate decimal to specified digits 12.349m.TruncateTo(2); // 12.34m

int extensions:

// round int as k, m, g 1000.Round(); // "1k" 1000000.Round(); // "1m" 1500.Round(); // "1k" 1500.Round(1); // "1.5k"

Graph extensions:

// if graph is cyclic (used for deadlock detection) bool isCyclic = graph.IsCyclic();

StringBuilder extensions:

// instead of buffer.AppendLine(string.Format(format, args)) buffer.AppendLine(format, args);
// reverse StringBuilder in-place buffer.Reverse();

Dictionary extensions:

// for key in dictionary, get value if exists or default / specified value var value = dictionary.GetValueOrDefault(key); var value = dictionary.GetValueOrDefault(key, other);
// get dictionary as readonly var dictionaryReadonly = dictionary.AsReadOnly();

Wrapped extensions:

// wrap (box) any type to avoid using pass by ref parameters var intw = new Wrapped<int>(1); // or 1.Wrap(); // intw.Value = 1

BitSet:

BitSet bitset = new BitSet(10); // 0 to 10 inclusive bitset.Add(5); // add 5 bitset.Add(6); bitset.Remove(5); // remove 5 bitset.Remove(3); bitset.Toggle(3); // toggle 3 bool has2 = bitset.Has(2); // if has 2 bitset.Clear(); // remove all foreach(int item in bitset) { /**/ }

Circular Queue:

CircularQueue<int> cq = new CircularQueue<int>(capacity: 2); cq.Enqueue(1); cq.Enqueue(2); cq.Enqueue(3); cq.Enqueue(4); int head; head = cq.Dequeue(); // returns 3 head = cq.Dequeue(); // returns 4

Circular Stack:

CircularStack<int> cq = new CircularStack<int>(capacity: 2); cq.Push(1); cq.Push(2); cq.Push(3); cq.Push(4); int top; top = cq.Pop(); // returns 4 top = cq.Pop(); // returns 3

Deque:

Deque<int> dq = new Deque<int>(); Node<int> node = dq.Enqueue(1); dq.Enqueue(2); dq.Delete(node); // delete in O(1) time int i = dq.Dequeue(); // returns 2

LRU cache:

LruCache<int, int> cache = new LruCache<int, int>(5); cache.Insert(key: 2, value: 2); cache.Get(2); // returns value 2 var count = cache.Count(); // return 1 cache.IsEmpty(); // returns false cache.Remove(2); // removes 2 from cache cache.IsFull(); // returns false cache.Capacity(); // returns 5 cache.Clear(); // clears cache

Guid:

// guid.ToByteArray() is sensitive to endianness, but // guid.ToByteArrayMatchingStringRepresentation() is not and matches guid.ToString() // see https://stackoverflow.com/questions/9195551/why-does-guid-tobytearray-order-the-bytes-the-way-it-does var bytes = Guid.Parse(someGuid).ToByteArrayMatchingStringRepresentation(); // similar roundtrip method var guid = bytes.ToGuidMatchingStringRepresentation(); // same as someGuid // other than base16 (hex) formats var guidBase64 = guid.ToBase64String(); var guidBase64Url = guid.ToBase64UrlString(); var guidBase32 = guid.ToBase32String();

Base64, Base64Url:

var base64 = s.ToUtf8Bytes().Base64Encode(); var s = base64.Base64Decode().ToUtf8String(); var base64Url = s.ToUtf8Bytes().Base64UrlEncode(); var s = base64Url.Base64UrlDecode().ToUtf8String();

Random:

var nextItem = rng.NextItem(arrayOfItems);
var gaussian = rng.NextGaussian(mu: mu, sigma: sigma);
var s = rng.NextString(length: 10, charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
var doubleN = rng.NextDouble(minValue: 5.0d, maxValue: 10.0d);
var decimalN = rng.NextDecimal(minValue: 5.0m, maxValue: 10.0m);

Base16 (Hex):

note: net5.0+ has Convert.ToHexString(bytes), Convert.FromHexString(hex) which are faster than below.

var base16 = s.ToUtf8Bytes().Base16Encode(); var s = base16.Base16Decode().ToUtf8String(); // or var hex = s.ToUtf8Bytes().ToHexString(); var s = hex.FromHexString().ToUtf8String();

char extensions:

// all/most System.Char static utility functions var c = 'a'.ToUpper(); // returns 'A' var isLower = c.IsLower(); // returns false var isLetter = c.IsLetter(); // returns true

Base32:

// Douglas Crockford's Base32 impl var base32 = s.ToUtf8Bytes().Base32Encode(); var s = base32.Base32Decode().ToUtf8String();

About

A collection of utility C# extension methods.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published