Skip to content

Instantly share code, notes, and snippets.

@NDiiong
Forked from RhysC/Guard.cs
Created August 3, 2020 09:04
Show Gist options
  • Save NDiiong/671668dc67d04c40848ce97deff812b4 to your computer and use it in GitHub Desktop.
Save NDiiong/671668dc67d04c40848ce97deff812b4 to your computer and use it in GitHub Desktop.
Showing a proposed use of Guard with expression for static checks and correct name evaluation in exception messages
public static class Guard
{
public static void NotNull<T>(Expression<Func<T>> notNullableExpression) where T : class
{
var compliedExpression = notNullableExpression.Compile();
if (compliedExpression() == null)
{
var paramName = notNullableExpression.GetObjectNameGraph();
throw new ArgumentNullException(paramName);
}
}
public static void NotNullOrWhiteSpace(Expression<Func<string>> notNullableExpression)
{
var compliedExpression = notNullableExpression.Compile();
if (string.IsNullOrWhiteSpace(compliedExpression()))
{
var paramName = notNullableExpression.GetObjectNameGraph();
throw new ArgumentException("Must not be null or empty/whitepsace string", paramName);
}
}
public static void Require<T>(Expression<Func<T>> notNullableExpression, Expression<Predicate<T>> predicate) where T : class
{
var x = notNullableExpression.Compile();
if (!predicate.Compile()((x())))
{
var paramName = notNullableExpression.GetObjectNameGraph();
throw new ArgumentException("failed predicate : " + predicate.ToString(), paramName);
}
}
}
public static class PropertyNameEx
{
public static string GetObjectNameGraph<T>(this Expression<Func<T>> propertyExpression)
{
var lambda = propertyExpression as LambdaExpression;
if(lambda == null)
throw new Exception("Must be a LambdaExpression");
return string.Concat(GetPropertyNames(lambda.Body).Intersperse("."));
}
private static IEnumerable<string> GetPropertyNames(Expression expression)
{
var memberExpression = expression as MemberExpression;
if (memberExpression == null) yield break;
var member = memberExpression.Member as MemberInfo;//Lambda syntax may make the initial value a field (in a closure i assume)
if (member == null)
{
memberExpression.Member.Dump("Error");
throw new Exception("Expression member is not a property or field accessor");
}
foreach (var propertyName in GetPropertyNames(memberExpression.Expression))
{
yield return propertyName;
}
yield return member.Name;
}
private static IEnumerable<T> Intersperse<T>(this IEnumerable<T> items, T separator)
{
var first = true;
foreach (var item in items)
{
if (first)
first = false;
else
yield return separator;
yield return item;
}
}
}
void Main()
{
var message = new { Alpha = "A", Beta = (string)null, Gamma = new { Delta = "Hi"}};
var messageConcrete = new TestObj();
messageConcrete.Testy = "Franco";
try{
Guard.NotNull(()=>message);
Guard.NotNullOrWhiteSpace(()=>message.Gamma.Delta);
Guard.NotNull(()=>messageConcrete.Testy);
Guard.Require(()=>messageConcrete.Testy, t=> t == "Arnold");//abitary prdeicate
}
catch(Exception ex)
{
ex.Dump();
}
message = new { Alpha = "A", Beta = (string)null, Gamma = new { Delta = (string)null}};
try
{
Guard.NotNullOrWhiteSpace(()=>message.Gamma.Delta);
}
catch(Exception ex)
{
ex.Dump();
}
}
public class TestObj
{
public string Testy;//fields work ok
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment