Simplifying an expression selector - c#

At the moment i am using this code in a class i call "Ensure", it is essentially a shortcut class of static methods i use to make throwing exceptions easier, so i am not constantly having to write out a minimum of 3 lines to do an exception, it can all always be done on 1 line.
[DebuggerHidden, DebuggerStepThrough]
public static void ArgumentNotNull(object argument, string name)
{
if (argument == null)
{
throw new ArgumentNullException(name, "Cannot be null");
}
}
[DebuggerHidden, DebuggerStepThrough]
public static void ArgumentNotNull<T>(Expression<Func<T>> expr)
{
var e = (MemberExpression)expr.Body;
var val = GetValue<T>(e);
ArgumentNotNull(val, e.Member.Name);
}
My issue is, currently when calling Ensure.ArgumentNotNull, i either have to do:
Ensure.ArgumentNotNull(arg, "arg");
or
Ensure.ArgumentNotNull(() => arg);
As i need the name to be able to explain which argument caused the exception in the exception its self.
Is there a way of being able to call ArgumentNotNull without needing the () => part of the lambda and simply call Ensure.ArgumentNotNull(arg) and still be able to get the name of the argument that was passed, without having to specifically pass the name as well.

Is there a way of being able to call ArgumentNotNull without needing the () => part of the lambda and simply call Ensure.ArgumentNotNull(arg) and still be able to get the name of the argument that was passed
I doubt it, because values have no meta-data to determine if it was an argument passed in, a variable, or a literal. The value will not always be an argument - there's nothing preventing you from calling Ensure.ArgumentNotNull(null);.

this works
public static void ArgumentNotNull(object argument)
{
StackFrame stackFrame = new StackTrace(true).GetFrame(1);
string fileName = stackFrame.GetFileName();
int lineNumber = stackFrame.GetFileLineNumber();
var file = new System.IO.StreamReader(fileName);
for (int i = 0; i < lineNumber - 1; i++)
file.ReadLine();
string varName = file.ReadLine().Split(new char[] { '(', ')' })[1];
if (argument == null)
{
throw new ArgumentNullException(varName, "Cannot be null");
}
}
alternate answer to OP question
'and still be able to get the name of the argument that was passed, without having to specifically pass the name as well.'
Simplified lamdba will do the trick.
myObject.ArgumentNotNull(x=>x.SomeProperty); -- prop checking
myObject.ArgumentNotNull(x=>x); -- objchecking
[DebuggerHidden, DebuggerStepThrough]
public static void ArgumentNotNull<T>(this T obj, Expression<Func<T, object>> expr = null)
{
if (obj == null) throw new NullReferenceException();
var body = expr.Body as MemberExpression;
if (body == null)
{
var ubody = (UnaryExpression)expr.Body;
body = ubody.Operand as MemberExpression;
}
if (body != null)
{
var property = body.Member as PropertyInfo;
if (property == null) throw;
if (obj.GetType().GetProperty(property.Name).GetValue(obj, null) == null) throw new NullReferenceException();
}
else
{
var ubody = (UnaryExpression)expr.Body;
var property = ubody.Operand as MemberExpression;
if (property != null)
props[property.Member.Name] = obj.GetType()
.GetProperty(property.Member.Name)
.GetValue(obj, null);
if (obj.GetType().GetProperty(property.Member.Name).GetValue(obj, null) == null) throw new NullReferenceException();
}
}

I am not aware of any mechanism you could use for this without some degree of code clutter, except for the Fody.NullGuard mentioned by Aron (opt-out model only) and other AOP frameworks (PostSharp).
However, instead of using expression trees, which both result in significant runtime performance penalty and are limited in terms of syntax, you can use anonymous types. This approach is relatively good in terms of performance, with a couple of assumptions:
that the user of the API will use it for arguments assertion only
that details of anonymous types implementation in C# will not change significantly
The usage of the API will look something like:
void SomeMethod(object arg1, string arg2, List<int> arg3)
{
new { arg1, arg2, arg3 }.ShouldNotBeNull();
....
Implementation is too large to show here, so it can be found in this gist. Additionally, it can be extended for range validations, etc.

You really want to use Fody.NullGuard instead of your current solution if you are worried about making a mistake when calling throw new ArgumentNullException("argName");.
You use Fody.NullGuard like this
public class Sample
{
public void SomeMethod(string arg)
{
// throws ArgumentNullException if arg is null.
}
public void AnotherMethod([AllowNull] string arg)
{
// arg may be null here
}
}
After compilation, Fody will rewrite the IL so its functionally the same as
public class Sample
{
public void SomeMethod(string arg)
{
if(arg == null)
throws new ArgumentNullException("arg");
}
public void AnotherMethod(string arg)
{
}
}

Related

Specify certain properties of a type

I am trying to initialize objects for tests purposes. After initializing an object, I want to assert that all properties whose underlying type is a value type have a value that is not the default value of the property's type, with certain exceptions. I am not trying to recurse into sub-objects. For this purpose, I have the following:
public static void NoValueTypedPropertyHasDefaultValue<T>(this T t, params string[] exceptions)
where T: class
{
foreach (var property in typeof(T).GetProperties())
{
var propertyType = property.PropertyType;
if (propertyType.IsValueType && !exceptions.Any(x => x == property.Name))
{
var defaultValue = Activator.CreateInstance(propertyType);
object actualValue = property.GetValue(t);
Assert.NotEqual(defaultValue, actualValue);
}
}
}
Provided that everything has a parameterless constructor, it works. I'm not thrilled with the way I'm passing in strings for the exceptions. Is there a better way to do that?
You mentioned in the comments:
I'm not thrilled that the caller could just type in the string, in which case it would not survive a renaming of the property.
Making use of System.Linq.Expressions can give you compile-time safety allowing code such as:
var inst = new MyType { MyInt1 = 1 }; // Set MyInt1 but not MyInt2
inst.NoValueTypedPropertyHasDefaultValue(x => x.MyInt2); // Ignore MyInt2 from validation
The code looks like below (H/T to Retrieving Property name from lambda expression) :
public static class Extensions
{
public static void NoValueTypedPropertyHasDefaultValue<T>(this T t, params Expression<Func<T,object>>[] propertiesToIgnore)
where T : class
{
var propertyNamesToIgnore = propertiesToIgnore.Select(x => GetMemberInfo(x).Member.Name).ToArray();
foreach (var property in typeof(T).GetProperties())
{
var propertyType = property.PropertyType;
if (propertyType.IsValueType && !propertyNamesToIgnore.Contains(property.Name))
{
var defaultValue = Activator.CreateInstance(propertyType);
object actualValue = property.GetValue(t);
Assert.NotEqual(defaultValue, actualValue);
}
}
}
private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null)
throw new ArgumentNullException("method");
MemberExpression memberExpr = null;
if (lambda.Body.NodeType == ExpressionType.Convert)
{
memberExpr =
((UnaryExpression)lambda.Body).Operand as MemberExpression;
}
else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpr = lambda.Body as MemberExpression;
}
if (memberExpr == null)
throw new ArgumentException("method");
return memberExpr;
}
}
Live example: https://dotnetfiddle.net/W9Q4gN (Note I have replaced your Assert call with an exception just for testing)
However, if all of that looks a little bit crazy/overkill to you (and to some extent, it really is!!) remember you could have just used nameof with your original scheme. Using my example your code would have become:
var inst = new MyType { MyInt1 = 1 }; // Set MyInt1 but not MyInt2
inst.NoValueTypedPropertyHasDefaultValue(nameof(inst.MyInt2)); // Ignore MyInt2 from validation

How to get the name of a property sent as a parameter using a lambda

I could have a method like this:
public void MyMethod<T, TResult>( string propertyName, ... ){
var name = propertyName;
return {property with correct name from some object that is of type TResult}
}
And call it like this:
MyMethod<SomeClass>("SomePropertyName");
To get hold of the propertyname inside the method. However, I do not like sending that propertyname in as a string in case SomeClass changes in the future, and the compiler cannot verify that the propertyName matches a property of type TResult either.
I would much rather call it like this:
MyMethod<SomeClass>(c => c.SomePropertyName);
But I am unsure how my method would look like then. I have tried variants of this:
public void MyMethod<T>( Func<T,TResult> property, ... ){
var name = {do some cleverness on property here to extract the actual name of the property inside the expression};
return {property with correct name from some object that is of type TResult}
}
Are there any good clean way to do this in C#?
You can't investigate Func<> delegates with much detail. You want to interrogate an Expression.. something like this (not tested.. but should be close):
public void MyMethod<T>(Expression<Func<T,TResult>> expr, ... ){
var expression = (MemberExpression)expr.Body;
var name = expression.Member.Name;
// .. the rest here using "name"
}
Usage is the same:
MyMethod<User>(u => u.UserId); // name will be "UserId"
This is how I do this for a RaisePropertyChanged method
internal static class PropertySupport
{
public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
{
throw new ArgumentException("propertyExpression");
}
var property = memberExpression.Member as PropertyInfo;
if (property == null)
{
throw new ArgumentException("propertyExpression");
}
var getMethod = property.GetGetMethod(true);
if (getMethod.IsStatic)
{
throw new ArgumentException("propertyExpression");
}
return memberExpression.Member.Name;
}
}
and in the method using the PropertySupport :
protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
var propertyName = PropertySupport.ExtractPropertyName(propertyExpression);
this.RaisePropertyChanged(propertyName);
}
I can use it simply with
RaisePropertyChanded<String>(() => this.MyString);
as you can see, the lambda is very simple.
Would [callermembername] work for you? You'd use it like:
public void MyMethod<T>([CallerMemberName]string caller = null){
//leave caller blank and it will put the name of the calling member in as a string
}
http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute(v=vs.110).aspx

Get non-static method name inside static method

I am trying to do something rather simple but not sure if there's any way around simply creating a dummy instance of my class.
I am trying to simply get the method name of a non-static method using some simple code:
static string GetMethodName(Func<string, int> function )
{
return function.Method.Name;
}
however I am trying to call this from MyStaticMethod like so and of course it is complaining:
private static void MyStaticMethod()
{
var a = GetMethodName(MyNonStaticMethod);
}
private int MyNonStaticMethod(string param1)
{
return 0;
}
Is there any way to accomplish this without creating a dummy instance of the containing class? obviously my case is more complex and I cannot simply make my non static method static (it requires an instance and has dependency bindings). Just wondering if this is possible as all I need is the name (so really don't need an instance). I am trying to get away from magic strings and want some compile time errors when things change.
edit: I've created a static helper class
i have a generic method:
public static string GetMemberName<T>(
Expression<Func<T, object>> expression)
{
if (expression == null)
{
throw new ArgumentNullException("expression");
}
return _GetMemberName(expression.Body);
}
private static string _GetMemberName(
Expression expression)
{
if (expression is MemberExpression)
{
var memberExpression =
(MemberExpression)expression;
return memberExpression.Member.Name;
}
if (expression is MethodCallExpression)
{
var methodCallExpression = (MethodCallExpression)expression;
return methodCallExpression.Method.Name;
}
if (expression is UnaryExpression)
{
var unaryExpression = (UnaryExpression)expression;
return GetMemberName(unaryExpression);
}
throw new ArgumentException("Unrecognized expression");
}
Of course you can do this. Use Expression<Func<YourInstanceClass, TReturn>> like this:
static string GetMethodName<TReturn>(Expression<Func<YourInstanceClass, TReturn>> function)
{
var call = function.Body as MethodCallExpression;
return call != null ? call.Method.Name : "not a single call expression";
}
now you can
var name = GetMethodName(a => a.MyNonStaticMethod("1"));
Console.WriteLine (name); //prints MyNonStaticMethod
where
public class YourInstanceClass
{
public int MyNonStaticMethod(string param1)
{
return 0;
}
}
I've made MyNonStaticMethod public, so that I can call it outside, but you can left it private and call it in static method inside a class

How to combine a) MEF and Generics in MEF composition engine?

I have the below program in MEF
Method 1:
public ObjectResult<PartnerListingStatement> GetCommissionListingRecords(string uRL, PortalConstant.DataSourceType DataSourceType)
{
ObjectResult<PartnerListingStatement> lstCommissionPartner = null;
var dataPlugin = DataPlugins.FirstOrDefault(i => i.Metadata["SQLMetaData"].ToString() == DataSourceType.EnumToString());
if (dataPlugin != null)
{
lstCommissionPartner = dataPlugin.Value.GetCommissionListingRecords(uRL);
}
return lstCommissionPartner;
}
Method B
public ObjectResult<CommissionEarned> GetCommissionPaidToPartners(string uRL, PortalConstant.DataSourceType DataSourceType)
{
ObjectResult<CommissionEarned> lstCommissionEarned = null;
var dataPlugin = DataPlugins.FirstOrDefault(i => i.Metadata["SQLMetaData"].ToString() == DataSourceType.EnumToString());
if (dataPlugin != null)
{
lstCommissionEarned = dataPlugin.Value.GetCommissionPaidToPartners(uRL);
}
return lstCommissionEarned;
}
Using generics or the like can these two be combined. Also the data types are different.
N.B.~ This question is different than Generics program to access WCF service from client
Thanks
The first question to ask after asking "Can I combine these methods?" is "What do these methods have in common?" I your case, the answer to that would be something like this:
public ObjectResult<***SomeType***> GetValues(string uRL, PortalConstant.DataSourceType DataSourceType)
{
ObjectResult<***SomeType***> ret = null;
var dataPlugin = DataPlugins.FirstOrDefault(i => i.Metadata["SQLMetaData"].ToString() == DataSourceType.EnumToString());
if (dataPlugin != null)
{
ret = dataPlugin.Value.***SomeMethod***(uRL);
}
return ret;
}
where ***SomeType*** and ***SomeMethod*** are the two meaningful differences between the methods. The deal with the type, make the method generic and replace all the ***SomeType*** with the generic parameter. To deal with the method, add a delegate parameter to the method. Based on its usage, the delegate will be of the Func<PluginType, string, ObjectResult<***SomeType***>> type where PluginType is whatever type dataPlugin.Value is. Now you have:
public ObjectResult<T> GetValues<T>( //do come up with a better name
string uRL,
PortalConstant.DataSourceType DataSourceType,
Func<PluginType, string, ObjectResult<T>> resultSelector)
{
ObjectResult<T> ret = null;
var dataPlugin = DataPlugins.FirstOrDefault(i => i.Metadata["SQLMetaData"].ToString() == DataSourceType.EnumToString());
if (dataPlugin != null)
{
ret = resultSelector(dataPlugin.Value, uRL);
}
return ret;
}
which is changes GetCommissionListingRecords to (the generic type should be inferred)
GetValues(uRL, DataSourceType, (p, u) => p.GetCommissionListingRecords(u));
and similarly for the other method.

get end values from lambda expressions method parameters

basically I want to get the values of the parameters of a called method like this:
var x = 1;
var a = 2;
var b = 3;
Do<HomeController>(o => o.Save(x, "Jimmy", a+b+5, Math.Sqrt(81)));
public static void Do<T>(Expression<Action<T>> expression) where T : Controller
{
// get the values 1,Jimmy,10,9 here
}
Well, you'd need to drill into the expression, find the MethodCallExpression, and then look at the arguments to it. Note that we don't have the value of o, so we've got to assume that the arguments to the method don't rely on that. Also we're still assuming that the lambda expression just relies on it being a MethodCallExpression?
EDIT: Okay, here's an edited version which evaluates the arguments. However, it assumes you're not really using the lambda expression parameter within the arguments (which is what the new object[1] is about - it's providing a null parameter, effectively).
using System;
using System.Linq.Expressions;
class Foo
{
public void Save(int x, string y, int z, double d)
{
}
}
class Program
{
static void Main()
{
var x = 1;
var a = 2;
var b = 3;
ShowValues<Foo>(o => o.Save(x, "Jimmy", a + b + 5, Math.Sqrt(81)));
}
static void ShowValues<T>(Expression<Action<T>> expression)
{
var call = expression.Body as MethodCallExpression;
if (call == null)
{
throw new ArgumentException("Not a method call");
}
foreach (Expression argument in call.Arguments)
{
LambdaExpression lambda = Expression.Lambda(argument,
expression.Parameters);
Delegate d = lambda.Compile();
object value = d.DynamicInvoke(new object[1]);
Console.WriteLine("Got value: {0}", value);
}
}
}
As Jon said you can check to see if the expression is a MethodCallExpression
class Program
{
static void Main(string[] args)
{
Program.Do<Controller>(c => c.Save(1, "Jimmy"));
}
public static void Do<T>(Expression<Action<T>> expression) where T : Controller
{
var body = expression.Body as MethodCallExpression;
if (body != null)
{
foreach (var argument in body.Arguments)
{
var constant = argument as ConstantExpression;
if (constant != null)
{
Console.WriteLine(constant.Value);
}
}
}
}
}
public class Controller
{
public void Save(int id, string name)
{
}
}
My universal answer is below. I hope it will help you and somebody else.
var dict = new Dictionary<string, object>();
var parameterExpressions = methodCallExpr.Arguments;
foreach (var param in method.GetParameters())
{
var parameterExpression = parameterExpressions[counter];
var paramValueAccessor = Expression.Lambda(parameterExpression);
var paramValue = paramValueAccessor.Compile().DynamicInvoke();
dict[param.Name] = paramValue;
}
Here is some code that is designed to work with any expression — in the sense that it doesn’t fundamentally assume that you are passing in a method-call expression. However, it is not complete. You will have to fill in the rest.
public static IEnumerable<object> ExtractConstants<T>(
Expression<Action<T>> expression)
{
return extractConstants(expression);
}
private static IEnumerable<object> extractConstants(Expression expression)
{
if (expression == null)
yield break;
if (expression is ConstantExpression)
yield return ((ConstantExpression) expression).Value;
else if (expression is LambdaExpression)
foreach (var constant in extractConstants(
((LambdaExpression) expression).Body))
yield return constant;
else if (expression is UnaryExpression)
foreach (var constant in extractConstants(
((UnaryExpression) expression).Operand))
yield return constant;
else if (expression is MethodCallExpression)
{
foreach (var arg in ((MethodCallExpression) expression).Arguments)
foreach (var constant in extractConstants(arg))
yield return constant;
foreach (var constant in extractConstants(
((MethodCallExpression) expression).Object))
yield return constant;
}
else
throw new NotImplementedException();
}
For the case that you have mentioned, this already works:
// Prints:
// Jimmy (System.String)
// 1 (System.Int32)
foreach (var constant in Ext.ExtractConstants<string>(
str => Console.WriteLine("Jimmy", 1)))
Console.WriteLine("{0} ({1})", constant.ToString(),
constant.GetType().FullName);
For more complex lambda expressions that employ other types of expression nodes, you will have to incrementally extend the above code. Every time you use it and it throws a NotImplementedException, here is what I do:
Open the Watch window in the debugger
Look at the expression variable and its type
Add the necessary code to handle that expression type
Over time the method will become more and more complete.
public override IQueryable<Image> FindAll(System.Linq.Expressions.Expression<Func<Image, dynamic>> Id)
{
dynamic currentType = Id.Parameters[0];
var id = currentType.Type.GUID;
var result = (_uniwOfWork as UnitOfWork).uspGetImages(id.ToString());
return FindAll();
}
use keyword dynamic.

Categories