//ModelFor(person =>person.Name);
public void ModelFor<TModel, TValue>(
Expression<Func<TModel, TValue>> expression)
{
//Result should be "Name"
string nameOfTValue = ????;
}
EDIT: After your edit, I think you are want the name of the member involved in the expression, assuming of course that the expression is a member-expression in the first place.
((MemberExpression)expression.Body).Member.Name
To be more robust, you can do:
var memberEx = expression.Body as MemberExpression;
if (memberEx == null)
throw new ArgumentException("Body not a member-expression.");
string name = memberEx.Member.Name;
(Not relevant anymore):
To get a System.Type that represents the type of the TValue type-argument, you can use the typeof operator.
You probably want:
typeof(TValue).Name
But also consider the FullName and AssemblyQualifiedName properties if appropriate.
This really has nothing to do with expression-trees; you can use this technique to get the type of a type-argument for any generic method.
#Ani: I don't think this is right, I think that he wants the name of the parameter in the expression of type TValue
If this is true... this works 1 level deep only but might be handy anyway:
var nameOfTValue = ((MemberExpression)expression.Body).Member.Name;
Here is smarter implementation that should be able to deal with multiple levels:
public class PropertyName{
public static string For<T>(
Expression<Func<T,object>> expression){
var body=expression.Body;
return GetMemberName(body);
}
public static string For(
Expression<Func<object>> expression){
var body=expression.Body;
return GetMemberName(body);
}
public static string GetMemberName(
Expression expression){
if(expression is MemberExpression){
var memberExpression=(MemberExpression)expression;
if(memberExpression.Expression.NodeType==
ExpressionType.MemberAccess)
return GetMemberName(memberExpression.Expression)
+"."+memberExpression.Member.Name;
return memberExpression.Member.Name;
}
if(expression is UnaryExpression){
var unaryExpression=(UnaryExpression)expression;
if(unaryExpression.NodeType!=ExpressionType.Convert)
throw new Exception(string.Format
("Cannot interpret member from {0}",expression));
return GetMemberName(unaryExpression.Operand);
}
throw new Exception
(string.Format("Could not determine member from {0}",expression));
}
}
Usage:
var fieldName=PropertyName.For<Customer>(x=>x.Address.Region);
//fieldName==Address.Region
Another trick, this can be combined with reflection nicely:
public static T Set<T,TProp>(this T o,
Expression<Func<T,TProp>> field,TProp value){
var fn=((MemberExpression)field.Body).Member.Name;
o.GetType().GetProperty(fn).SetValue(o,value,null);
return o;
}
Allows to directly set properties with ease, can be useful for test fixtures:
var customer=new Customer("firstName","lastName");
customer.Set(x=>x.Name, "different firstName");
Related
I am defining a collection of mappings in code at design time and then executing those mappings at run time after doing some data extraction :
public class FormExtractionMap<T>
{
public Expression<Func<T>> Destination { get; set; }
public string Source { get; set; }
}
Mapping Code:
var extractionRequest = new ExtractionRequest<PlanningApplication>
{
Mapping = new List<FormExtractionMap<PlanningApplication>>
{
new FormExtractionMap<PlanningApplication> {Destination = x => x.Site.Address.MapCoordinate.Eastings, Source = "site_address_easting"},
new FormExtractionMap<PlanningApplication> {Destination = x => x.Site.Address.MapCoordinate.Northings, Source = "site_address_northing"},
}
};
and then I'm looking through each of the mapping expressions to go and get the Source value (any Type) and then assign it to the Destination Expression (any Type).
foreach (var extractionMap in extractionRequest.Mapping)
{
extractionRequest.ExtractTo.Set(extractionMap.Destination, form.GetValue(extractionMap.Source));
}
I then have Expression extensions to create a setter, compile and do the property assignment.
public static TEntity Set<TEntity, TProperty>(
this TEntity obj,
Expression<Func<TEntity, TProperty>> selector,
TProperty value)
{
var setterExpr = CreateSetter(selector);
setterExpr.Compile()(obj, value);
return obj;
}
private static Expression<Action<TEntity, TProperty>> CreateSetter<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> selector)
{
ParameterExpression valueParameterExpression = Expression.Parameter(typeof(TProperty), "value");
Expression targetExpression = selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body;
var newValue = Expression.Parameter(selector.Body.Type);
return Expression.Lambda<Action<TEntity, TProperty>>
(
Expression.Assign(targetExpression, Expression.Convert(valueParameterExpression, targetExpression.Type)),
selector.Parameters.Single(),
valueParameterExpression
);
}
if Source is a string and the Destination is a string the value is assigned fine. If the Destination is a double on setterExpr.Compile()(obj, value); I get :
System.InvalidCastException : Unable to cast object of type
'System.String' to type 'System.Double'.
I thought the "Expression.Convert" was handling the type conversion but clearly not. What am I doing wrong please ?
So, I did eventually solve this. Expression.Convert is akin to an explicit cast (Foo)Bar, not as "Convert" implies. I ended up with:
private static Expression<Action<TEntity, TProperty>> CreateSetter<TEntity, TProperty>(
Expression<Func<TEntity, TProperty>> selector, Type valueParameterType)
{
ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object), "value");
Expression targetExpression = selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body;
var resultBody = ConvertToDestination(valueParameterExpression, valueParameterType, targetExpression);
return Expression.Lambda<Action<TEntity, TProperty>>
(
Expression.Assign(targetExpression, resultBody),
selector.Parameters.Single(),
valueParameterExpression
);
}
private static Expression ConvertToDestination(ParameterExpression valueParameterExpression, Type valueParameterType, Expression targetExpression)
{
if (valueParameterType == typeof(string))
{
switch (targetExpression.Type)
{
case Type _ when targetExpression.Type == typeof(double):
return Expression.Call(typeof(Convert), "ToDouble", null, valueParameterExpression);
case Type _ when targetExpression.Type == typeof(int):
return Expression.Call(typeof(Convert), "ToInt", null, valueParameterExpression);
default:
return Expression.Convert(valueParameterExpression, targetExpression.Type);
}
}
return Expression.Convert(valueParameterExpression, targetExpression.Type);
}
However, I thought it was messy, verbose and frankly unnecessary as I was able to implement similar functionality using AutoMapper in a few hours. Automapper does a better job of type conversion, caching the maps etc. So the real solution was re-factor and don't re-invent the wheel.
I know there are a few answers on the site on this and i apologize if this is in any way duplicate, but all of the ones I found does not do what I am trying to do.
I am trying to specify method info so I can get the name in a type safe way by not using strings.
So I am trying to extract it with an expression.
Say I want to get the name of a method in this interface:
public interface IMyInteface
{
void DoSomething(string param1, string param2);
}
Currently I can get the name using THIS method:
MemberInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
return ((MethodCallExpression)expression.Body).Method;
}
I can call the helper method as follows:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething(null, null));
Console.WriteLine(methodInfo.Name);
But I am looking for the version that I can get the method name without specifying the parameters (null, null)
like this:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething);
But all attempts fail to compile
Is there a way to do this?
x => x.DoSomething
In order to make this compilable I see only two ways:
Go non-generic way and specify it's parameter as Action<string, string>
Specify Action<string, string> as your target delegate type by yourself: GetMethodInfo<IMyInteface>(x => new Action<string,string>(x.DoSomething))
if you are ok to go with second one, which allows you to omit arguments then you can write your GetMethodInfo method as follows:
MemberInfo GetMethodInfo<T>(Expression<Func<T, Delegate>> expression)
{
var unaryExpression = (UnaryExpression) expression.Body;
var methodCallExpression = (MethodCallExpression) unaryExpression.Operand;
var methodInfoExpression = (ConstantExpression) methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo) methodInfoExpression.Value;
return methodInfo;
}
It works for your interface, but probably some generalization will be required to make this working with any method, that's up to you.
The following is compatible with .NET 4.5:
public static string MethodName(LambdaExpression expression)
{
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodCallObject = (ConstantExpression)methodCallExpression.Object;
var methodInfo = (MethodInfo)methodCallObject.Value;
return methodInfo.Name;
}
You can use it with expressions like x => x.DoSomething, however it would require some wrapping into generic methods for different types of methods.
Here is a backwards-compatible version:
private static bool IsNET45 = Type.GetType("System.Reflection.ReflectionContext", false) != null;
public static string MethodName(LambdaExpression expression)
{
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
if (IsNET45)
{
var methodCallObject = (ConstantExpression)methodCallExpression.Object;
var methodInfo = (MethodInfo)methodCallObject.Value;
return methodInfo.Name;
}
else
{
var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo)methodInfoExpression.Value;
return methodInfo.Name;
}
}
Check this sample code on Ideone.
Note, that Ideone does not have .NET 4.5.
The problem with this is that x.DoSomething represents a method group. And you have to somehow explicitly specify what delegate type do you want to convert that method group into, so that the correct member of the group can be selected. And it doesn't matter if that group contains only one member.
The compiler could infer that you mean that one, but it doesn't do that. (I think it's this way so that your code won't break if you add another overload of that method.)
Snowbear's answer contains good advice on possible solutions.
This is a new answer to an old question, but responds to the "verbose" complaint of the accepted answer. It requires more code, but the result is a syntax like:
MemberInfo info = GetActionInfo<IMyInterface, string, string>(x => x.DoSomething);
or, for methods with a return value
MemberInfo info = GetFuncInfo<IMyInterface, object, string, string>(x => x.DoSomethingWithReturn);
where
object DoSomethingWithReturn(string param1, string param2);
Just like the framework provides Action<> and Func<> delegates up to 16 parameters, you have to have GetActionInfo and GetFuncInfo methods that accept up to 16 parameters (or more, although I'd think refactoring is wise if you have methods with 16 parameters). A lot more code, but an improvement in the syntax.
If you are ok with using the nameof() operator you can use the following approach.
One of the benefits is not having to unwrap an expression tree or supply default values or worry about having a non-null instance of the type with the method.
// As extension method
public static string GetMethodName<T>(this T instance, Func<T, string> nameofMethod) where T : class
{
return nameofMethod(instance);
}
// As static method
public static string GetMethodName<T>(Func<T, string> nameofMethod) where T : class
{
return nameofMethod(default);
}
Usage:
public class Car
{
public void Drive() { }
}
var car = new Car();
string methodName1 = car.GetMethodName(c => nameof(c.Drive));
var nullCar = new Car();
string methodName2 = nullCar.GetMethodName(c => nameof(c.Drive));
string methodName3 = GetMethodName<Car>(c => nameof(c.Drive));
If your application would allow a dependency on Moq (or a similar library), you could do something like this:
class Program
{
static void Main(string[] args)
{
var methodName = GetMethodName<IMyInteface>(x => new Action<string,string>(x.DoSomething));
Console.WriteLine(methodName);
}
static string GetMethodName<T>(Func<T, Delegate> func) where T : class
{
// http://code.google.com/p/moq/
var moq = new Mock<T>();
var del = func.Invoke(moq.Object);
return del.Method.Name;
}
}
public interface IMyInteface
{
void DoSomething(string param1, string param2);
}
Suppose I have:
class Person
{
[ColumnAttribute("ID"]
public int Id;
[ColumnAttribute("Name"]
public string Name;
[ColumnAttribute("DateOfBirth"]
public date BirthDate;
}
i want to create a method that will be called as following
GetPropertyColumn<Person>(e=>e.Name)
this method will return a string that is defined by the ColumnAttribute attribute.
the problem is that i am not able to define this method.
i tried
public string GetPropertyColumn<T,U>(Expression<Func<T, U>> Lamda)
but the problem is that i can only specify the T and not the U so its not working.
any help?
thanks
Edit:
thanks for the answers but i got a lot of answers in which you need to instantinate Person but i dont want to.
because i only want to know the column given a property defined inside a Class.
If you have a generic method with 2 generic types (T and U) then both most be specified, or both most be inferred. If that isn't possible, consider an expression taking Func<T,object> (remove U), and remove the cast/convert node from the expression tree when inspecting it at runtime. You can also do things to make both types inferred, but that may need more of a refactor.
[EDIT 3]
public static string GetPropertyColumn<T>(Expression<Func<T,object>> f)
{
Type t = typeof(T);
MemberExpression memberExpression = null;
if (f.Body.NodeType == ExpressionType.Convert)
{
memberExpression = ((UnaryExpression)f.Body).Operand as MemberExpression;
}
else if (f.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpression = f.Body as MemberExpression;
}
string name = memberExpression.Member.Name;
System.Reflection.FieldInfo fi = t.GetField(name);
object[] attrs = fi.GetCustomAttributes(true);
foreach (var attr in attrs)
{
ColumnAttribute columnAttr = attr as ColumnAttribute;
if (columnAttr != null)
{
return columnAttr.Name;
}
}
return string.Empty;
}
using:
Console.WriteLine(GetPropertyColumn<Person>(e => e.Name));
Make it an extension method:
static class ExtensionMethods
{
public static string GetPropertyColumn<T,U>(this T obj, Expression<Func<T, U>> selector)
{
... // whatever
}
}
And use it as follows:
Person person = ...
string propertyColumn = person.GetPropertyColumn(p => p.Name);
You don't need to specify T, because it's inferred from the first parameter, and you don't need to specify U either because it is inferred from the return type of the lambda
Note that you don't need to define it as an extension method, it could also be a normal method. You would then use it like that:
Person person = ...
string propertyColumn = GetPropertyColumn(person, p => p.Name);
I'd like to be able to generate a compiled expression to set a property, given the lambda expression that provides the "get" method for a property.
Here's what I'm looking for:
public Action<int> CreateSetter<T>(Expression<Func<T, int>> getter)
{
// returns a compiled action using the details of the getter expression tree, or null
// if the write property is not defined.
}
I'm still trying to understand the various types of Expression classes, so if you can point me in the right direction that would be great.
Using #Ani's answer as a starting point, you can use the following to generate a compiled expression.
[TestMethod]
public void CreateSetterFromGetter()
{
Action<Person, int> ageSetter = InitializeSet((Person p) => p.Age);
Action<Person, string> nameSetter = InitializeSet((Person p) => p.Name);
Person p1 = new Person();
ageSetter(p1, 29);
nameSetter(p1, "John");
Assert.IsTrue(p1.Name == "John");
Assert.IsTrue(p1.Age == 29);
}
public class Person { public int Age { get; set; } public string Name { get; set; } }
public static Action<TContainer, TProperty> InitializeSet<TContainer, TProperty>(Expression<Func<TContainer, TProperty>> getter)
{
PropertyInfo propertyInfo = (getter.Body as MemberExpression).Member as PropertyInfo;
ParameterExpression instance = Expression.Parameter(typeof(TContainer), "instance");
ParameterExpression parameter = Expression.Parameter(typeof(TProperty), "param");
return Expression.Lambda<Action<TContainer, TProperty>>(
Expression.Call(instance, propertyInfo.GetSetMethod(), parameter),
new ParameterExpression[] { instance, parameter }).Compile();
}
You should cache the compiled expression to keep it handy for multiple uses.
You could of course walk the expression-tree and then use Delegate.CreateDelegate to create the appropriate Action<,>. It's quite simple, except for all of the validation-checks (I'm unsure if I've covered everything):
I'm no expression-tree expert, but I don't think building an expression-tree and then calling Compile is possible here since expression-trees can't contain assignment statements, as far as I know. (EDIT: Apparently, these have been added in .NET 4. It's a hard-to-find feature since the C# compiler doesn't seem to be able to build them from lambdas).
public static Action<TContaining, TProperty>
CreateSetter<TContaining, TProperty>
(Expression<Func<TContaining, TProperty>> getter)
{
if (getter == null)
throw new ArgumentNullException("getter");
var memberEx = getter.Body as MemberExpression;
if (memberEx == null)
throw new ArgumentException("Body is not a member-expression.");
var property = memberEx.Member as PropertyInfo;
if (property == null)
throw new ArgumentException("Member is not a property.");
if(!property.CanWrite)
throw new ArgumentException("Property is not writable.");
return (Action<TContaining, TProperty>)
Delegate.CreateDelegate(typeof(Action<TContaining, TProperty>),
property.GetSetMethod());
}
Usage:
public class Person { public int Age { get; set; } }
...
static void Main(string[] args)
{
var setter = CreateSetter((Person p) => p.Age);
var person = new Person();
setter(person, 25);
Console.WriteLine(person.Age); // 25
}
Do note that this creates an open instance delegate, meaning that it's not bound to any particular instance of TContaining. It's simple to modify it to be bound to a specific instance; you'll have to pass a TContaining as well to the method and then use a different overload of Delegate.CreateDelegate. The signature of the method would then look something like:
public static Action<TProperty> CreateSetter<TContaining, TProperty>
(Expression<Func<TContaining, TProperty>> getter, TContaining obj)
Pointers only I'm afraid (I'm not at a pc) - but;
the lambda's .Body will most likely be MemberExpression
do a safe cast (as etc) and access the .Member
since you belive this a property, this should be a PropertyInfo, so test/cast etc
from a PropertyInfo, call GetSetMethod() to get the corresponding MethodInfo
use Delegate.CreateDelegate to get that as a delegate (passing the action type)
finally, cast the Delegate returned onto the expected delegate type
I am trying to write a function that will pull the name of a property and the type using syntax like below:
private class SomeClass
{
Public string Col1;
}
PropertyMapper<Somewhere> propertyMapper = new PropertyMapper<Somewhere>();
propertyMapper.MapProperty(x => x.Col1)
Is there any way to pass the property through to the function without any major changes to this syntax?
I would like to get the property name and the property type.
So in the example below i would want to retrieve
Name = "Col1" and Type = "System.String"
Can anyone help?
Here's enough of an example of using Expressions to get the name of a property or field to get you started:
public static MemberInfo GetMemberInfo<T, U>(Expression<Func<T, U>> expression)
{
var member = expression.Body as MemberExpression;
if (member != null)
return member.Member;
throw new ArgumentException("Expression is not a member access", "expression");
}
Calling code would look like this:
public class Program
{
public string Name
{
get { return "My Program"; }
}
static void Main()
{
MemberInfo member = ReflectionUtility.GetMemberInfo((Program p) => p.Name);
Console.WriteLine(member.Name);
}
}
A word of caution, though: the simple statment of (Program p) => p.Name actually involves quite a bit of work (and can take measurable amounts of time). Consider caching the result rather than calling the method frequently.
This can be easily done in C# 6. To get the name of property use nameof operator.
nameof(User.UserId)
and to get type of property use typeof operator.
typeof(User.UserId)
I found this very useful.
public class PropertyMapper<T>
{
public virtual PropertyInfo PropertyInfo<U>(Expression<Func<T, U>> expression)
{
var member = expression.Body as MemberExpression;
if (member != null && member.Member is PropertyInfo)
return member.Member as PropertyInfo;
throw new ArgumentException("Expression is not a Property", "expression");
}
public virtual string PropertyName<U>(Expression<Func<T, U>> expression)
{
return PropertyInfo<U>(expression).Name;
}
public virtual Type PropertyType<U>(Expression<Func<T, U>> expression)
{
return PropertyInfo<U>(expression).PropertyType;
}
}
I made this little class to follow the original request.
If you need the name of the property you can use it like this:
PropertyMapper<SomeClass> propertyMapper = new PropertyMapper<SomeClass>();
string name = propertyMapper.PropertyName(x => x.Col1);
I just thought I would put this here to build on the previous approach.
public static class Helpers
{
public static string PropertyName<T>(Expression<Func<T>> expression)
{
var member = expression.Body as MemberExpression;
if (member != null && member.Member is PropertyInfo)
return member.Member.Name;
throw new ArgumentException("Expression is not a Property", "expression");
}
}
You can then call it in the following fashion:
Helpers.PropertyName(() => TestModel.TestProperty);
I should also point out that with VS 2015 and C# 6.0 you can simply use nameof.
https://msdn.microsoft.com/en-us/library/dn986596.aspx