Skip to content

Instantly share code, notes, and snippets.

@madelson
Created February 23, 2014 22:09
Show Gist options
  • Save madelson/9178059 to your computer and use it in GitHub Desktop.
Save madelson/9178059 to your computer and use it in GitHub Desktop.
10 utility functions (part 2 of 2)
namespace CodeDucky
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public static class Throw
{
/// <summary>
/// Throws an <see cref="ArgumentNullException"/> if the given value is null
/// </summary>
public static void IfNull<T>(T value, string parameterName)
{
Throw<ArgumentNullException>.If(value == null, parameterName);
}
/// <summary>
/// Throws an <see cref="ArgumentException"/> if the given condition is true
/// </summary>
public static void If(bool condition, string parameterName)
{
Throw<ArgumentException>.If(condition, parameterName);
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> if the given value is outside of the specified range
/// </summary>
public static void IfOutOfRange<T>(T value, string paramName, T? min = null, T? max = null)
where T : struct, IComparable<T>
{
if (min.HasValue && value.CompareTo(min.Value) < 0)
{
throw new ArgumentOutOfRangeException(paramName, string.Format("Expected: >= {0}, but was {1}", min, value));
}
if (max.HasValue && value.CompareTo(max.Value) > 0)
{
throw new ArgumentOutOfRangeException(paramName, string.Format("Expected: <= {0}, but was {1}", max, value));
}
}
}
public static class Throw<TException>
where TException : Exception
{
/// <summary>
/// Throws an exception of type <see cref="TException"/> if the condition is true
/// </summary>
public static void If(bool condition, string message)
{
if (condition)
{
throw Create(message);
}
}
/// <summary>
/// As <see cref="Throw.If(bool, string)"/>, but allows the message to be specified lazily. The message function will only be evaluated
/// if the condition is true
/// </summary>
public static void If(bool condition, Func<string> message)
{
if (condition)
{
throw Create(message());
}
}
private static TException Create(string message)
{
return (TException)Activator.CreateInstance(typeof(TException), message);
}
}
}
namespace CodeDucky
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public static class Helpers
{
/// <summary>
/// Bounds a value within a range
/// </summary>
public static T Capped<T>(this T @this, T? min = null, T? max = null)
where T : struct, IComparable<T>
{
return min.HasValue && @this.CompareTo(min.Value) < 0 ? min.Value
: max.HasValue && @this.CompareTo(max.Value) > 0 ? max.Value
: @this;
}
/// <summary>
/// Type-safely casts the given value to the specified type
/// </summary>
public static T As<T>(this T @this)
{
return @this;
}
/// <summary>
/// Invokes the given function on the given object if and only if the given object is not null. Otherwise,
/// the value specified by "ifNullReturn" is returned
/// </summary>
public static TResult NullSafe<TObj, TResult>(
this TObj obj,
Func<TObj, TResult> func,
TResult ifNullReturn = default(TResult))
{
Throw.IfNull(func, "func");
return obj != null ? func(obj) : ifNullReturn;
}
}
}
namespace CodeDucky
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public static class Traverse
{
/// <summary>
/// Returns an <see cref="IEnumerable{T}"/> based on traversing the "linked list" represented by the head node
/// and the next function. The list terminates when a null node is reached
/// </summary>
/// <typeparam name="T">the type of node in the list</typeparam>
/// <param name="node">the head node of the list</param>
/// <param name="next">a function that, given a node in the list, generates the next node in the list</param>
public static IEnumerable<T> Along<T>(T node, Func<T, T> next)
where T : class
{
Throw.IfNull(next, "next");
for (var current = node; current != null; current = next(current))
{
yield return current;
}
}
}
}
namespace CodeDucky
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public static class CollectionHelpers
{
public static bool CollectionEquals<T>(this IEnumerable<T> @this, IEnumerable<T> that, IEqualityComparer<T> comparer = null)
{
// this is optional; if you want to be consistent with SequenceEqual, just throw exceptions if either argument is null instead
if (@this == null) { return that == null; }
else if (that == null) { return false; }
var countedItems = @this.GroupBy(t => t, comparer).ToDictionary(
g => g.Key,
g => g.Count(),
comparer);
foreach (var item in that)
{
int count;
if (!countedItems.TryGetValue(item, out count)) { return false; }
if (count - 1 == 0) { countedItems.Remove(item); }
else { countedItems[item] = count - 1; }
}
return countedItems.Count == 0;
}
/// <summary>
/// If the given key is present in the dictionary, returns the value for that key. Otherwise, executes the given value factory
/// function, adds the result to the dictionary, and returns that result
/// </summary>
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> @this, TKey key, Func<TKey, TValue> valueFactory)
{
TValue value;
if ([email protected](key, out value)) { @this.Add(key, value = valueFactory(key)); }
return value;
}
}
}
namespace CodeDucky
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
public static class ReflectionHelpers
{
/// <summary>
/// Gets generic arguments from the given type for the given type definition
/// </summary>
public static Type[] GetGenericArguments(this Type @this, Type genericTypeDefinition)
{
Throw.IfNull(@this, "this");
Throw.IfNull(genericTypeDefinition, "genericTypeDefinition");
Throw.If(!genericTypeDefinition.IsGenericTypeDefinition, "genericTypeDefinition: must be a generic type definition");
if (genericTypeDefinition.IsInterface)
{
var @interface = @this.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericTypeDefinition);
return @interface.NullSafe(i => i.GetGenericArguments(), Type.EmptyTypes);
}
if (@this.IsGenericType && @this.GetGenericTypeDefinition() == genericTypeDefinition)
{
return @this.GetGenericArguments();
}
return @this.BaseType.NullSafe(t => t.GetGenericArguments(genericTypeDefinition), Type.EmptyTypes);
}
/// <summary>
/// Returns the method referenced by the given expression
/// </summary>
public static MethodInfo GetMethod<TInstance>(Expression<Action<TInstance>> methodExpression)
{
Throw.IfNull(methodExpression, "methodExpression");
var methodCall = (MethodCallExpression)methodExpression.Body;
return methodCall.Method;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment