C# Reflection - Get PropertyInfo without a string [duplicate] - c#

This question already has answers here:
How to get the PropertyInfo of a specific property?
(5 answers)
Closed 8 years ago.
I have a property in Myclass:
public class MyClass{
public string FirstName {get;set;}
}
How can I get the PropertyInfo (using GetProperty("FirstName")) without a string?
Today I use this:
PropertyInfo propertyTitleNews = typeof(MyClass).GetProperty("FirstName");
Is there a way for use like this:
PropertyInfo propertyTitleNews = typeof(MyClass).GetProperty(MyClass.FirstName);
?

See here. The idea is to use Expression Trees.
public static string GetPropertyName<T, TReturn>(Expression<Func<T, TReturn>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return body.Member.Name;
}
And then use it like:
var name = GetPropertyName<MyClass, string>(c => c.FirstName);
A bit cleaner solution would be if one would not required to specify so much generic parameters. And it is possible via moving MyClass generic param to util class:
public static class TypeMember<T>
{
public static string GetPropertyName<TReturn>(Expression<Func<T, TReturn>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return body.Member.Name;
}
}
Then usage will be cleaner:
var name = TypeMember<MyClass>.GetPropertyName(c => c.FirstName);

Another possibility, beside Ivan Danilov's answer, is to provide an extension method:
public static class PropertyInfoExtensions
{
public static string GetPropertyName<TType, TReturnType>(
this TType #this,
Expression<Func<TType, TReturnType>> propertyId)
{
return ((MemberExpression)propertyId.Body).Member.Name;
}
}
And then use it like this:
MyClass c;
PropertyInfo propertyTitleNews = c.GetPropertyName(x => x.FirstName);
The drawback is that you need an instance, but an advantage is that you don't need to supply generic arguments.

You could do that
var property = ExpressionExtensions.GetProperty<MyClass>(o => o.FirstName);
With this helper :
public static PropertyInfo GetProperty<T>(Expression<Func<T, Object>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return typeof(T).GetProperty(body.Member.Name);
}

Related

Pass property name by lambda expression for reading attribute values

I have found this solution:
public static T GetAttributeFrom<T>(this object instance, string propertyName) where T : Attribute
{
var attrType = typeof(T);
var property = instance.GetType().GetProperty(propertyName);
return (T)property .GetCustomAttributes(attrType, false).First();
}
Code by jgauffin from How to retrieve Data Annotations from code
I always use the extension this way:
foo.GetAttributeFrom<StringLengthAttribute>(nameof(Foo.Bar)).MaximumLength
Is there a way to pass the propertyName by using a lambda like:
foo.GetAttributeFrom<StringLengthAttribute>(f => f.Bar).MaximumLength
Thank you in advance!
You can split the work into two functions in order to bypass specifying all generic parameter type for a generic method restriction
public static object[] GetPropertyAttributes<TObject, TProperty>(
this TObject instance,
Expression<Func<TObject, TProperty>> propertySelector)
{
//consider handling exceptions and corner cases
var propertyName = ((PropertyInfo)((MemberExpression)propertySelector.Body).Member).Name;
var property = instance.GetType().GetProperty(propertyName);
return property.GetCustomAttributes(false);
}
public static T GetFirst<T>(this object[] input) where T : Attribute
{
//consider handling exceptions and corner cases
return input.OfType<T>().First();
}
then use it like
foo.GetPropertyAttributes(f => f.Bar)
.GetFirst<StringLengthAttribute>()
.MaximumLength;
The method can be like this:
public static TAtt GetAttribute<TAtt,TObj,TProperty>(this Rootobject inst,
Expression<Func<TObj,TProperty>> propertyExpression)
where TAtt : Attribute
{
var body = propertyExpression.Body as MemberExpression;
var expression = body.Member as PropertyInfo;
var ret = (TAtt)expression.GetCustomAttributes(typeof(TAtt), false).First();
return ret;
}
If you have a class like this with the attribute:
public class Rootobject
{
[StringLengthAttribute(10)]
public string Name { get; set; }
}
Then you will use it like this:
var obj = new Rootobject();
var max = obj.GetAttribute<StringLengthAttribute, Rootobject, string>((x) => x.Name)
.MaximumLength;
Improvements
Add error checking in case the attribute is not found or the lambda is not for a property etc.

Dynamically creating an expression which selects an objects property

I want to be able to build up an expression dynamically, which is essentially a property selector.
I am trying to use this so I can provide a flexible search UI and then translate the selected search parameters to an Entity Framework query.
I have most of what I need thanks to another library I am using, but am missing the final part which translates my query string parameters to the appropriate expression selector the other library requires.
The library takes an argument of :
Expression<Func<TObject, TPropertyType>>
An example of how this would be coded if baked into an application would be :
Expression<Func<MyObject, int>> expression = x=> x.IntegerProperty;
However, I need to be able to generate this expression dynamically, as the important point is that all I will know is the type of object (MyObject) and the property name as a string value ("IntegerProperty"). The property value will obviously map to an property on the object which could be of any non complex type.
So essentially I think I am wanting to find a way to build up the expression dynamically which specifies the correct object property to return and where the return value is determined by that property type.
psuedo code :
string ObjectPropertyName
Type ObjectType
Type ObjectPropertyType = typeof(ObjectType).GetProperty(ObjectPropertyName).Property
Expression<Func<[ObjectType], [ObjectPropertyType]>> expression = x=> x.[ObjectPropertyName];
Update :
I have got as far as this
ParameterExpression objectParameter = Expression.Parameter(type, "x");
MemberExpression objectProperty = Expression.Property(objectParameter, "PropertyNameString");
Expression<Func<ObjectType, int>> expression = Expression.Lambda<Func<ObjectType, int>>(objectProperty, objectParameter);
But the problem I have with this is that the return type is not always an int but may be some other type.
Doing what you asked is bit tricky but not impossible. Since the property type is not known until run time so you can not declare the Expression<Func<,>> so it would be done by reflection.
public static class QueryableExtension
{
public static object Build<Tobject>(this Tobject source, string propertyName)
{
var propInfo = typeof(Tobject).GetProperty(propertyName);
var parameter = Expression.Parameter(typeof(Tobject), "x");
var property = Expression.Property(parameter, propInfo);
var delegateType = typeof(Func<,>)
.MakeGenericType(typeof(Tobject), propInfo.PropertyType);
var lambda = GetExpressionLambdaMethod()
.MakeGenericMethod(delegateType)
.Invoke(null, new object[] { property, new[] { parameter } });
return lambda;
}
public static MethodInfo GetExpressionLambdaMethod()
{
return typeof(Expression)
.GetMethods()
.Where(m => m.Name == "Lambda")
.Select(m => new
{
Method = m,
Params = m.GetParameters(),
Args = m.GetGenericArguments()
})
.Where(x => x.Params.Length == 2
&& x.Args.Length == 1
)
.Select(x => x.Method)
.First();
}
}
Usage -
var expression = testObject.Build("YourPropertyName");
Now this will build the Expression you desired with return type of property. But since we don't know about your library but I suggest you to call your library method via reflection and pass the expression wrapped under object.
As I mentioned in the comments, building expression without knowing the property type is easy (even with nested property support):
static LambdaExpression MakeSelector(Type objectType, string path)
{
var item = Expression.Parameter(objectType, "item");
var body = path.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);
return Expression.Lambda(body, item);
}
But then you'll need to find a way to call your generic library method - using reflection or dynamic call.
If you have both ObjectType and ObjectPropertyType as generic type parameters, you can use the Expression class to do something like this:
public static Expression<Func<TObject, TPropertyType>> Generate<TObject, TPropertyType>(
string property_name)
{
var parameter = Expression.Parameter(typeof (TObject));
return Expression.Lambda<Func<TObject, TPropertyType>>(
Expression.Property(parameter, property_name), parameter);
}
There is old intresting library DynamicLinq. May be it will be useful for you. It extends System.Linq.Dynamic to support execution of Lambda expressions defined in a string. With use of DynamicLinq you can do somethink like:
public class IndexViewModel
{
public bool HasPassword { get; set; }
public string PhoneNumber { get; set; }
public bool TwoFactor { get; set; }
public bool BrowserRemembered { get; set; }
}
//...........
Expression<Func<IndexViewModel, bool>> ex =
System.Linq.Dynamic.DynamicExpression.ParseLambda<IndexViewModel, bool>("TwoFactor");
var model = new ReactJs.NET.Models.IndexViewModel() { TwoFactor = true };
var res = ex.Compile()(model);
// res == true
System.Diagnostics.Debug.Assert(res);

Get the name of a method using an expression

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);
}

help defining a generic method along with expression tree parameter

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);

Get the name of a property by passing it to a method

StackOverflow user jolson had a very nice piece of code that exemplifies how one can register menthods without using strings, but expression trees here.
Is it possible to have something similar for properties instead of methods? To pass a property (not the name of the property) and inside the method to obtain the property name?
Something like this:
RegisterMethod(p => p.Name)
void RegisterMethod(Expression??? propertyExpression) where T : Property ???
{
string propName = propertyExpression.Name;
}
Thanks.
I posted a full example of this here (see also the post about "this" underneath it)
Note it deals with the LambdaExpression etc. As an update to the code as posted, you can add a bit more to make it easier to use in some scenarios:
static class MemberUtil<TType>
{
public static string MemberName<TResult>(Expression<Func<TType, TResult>> member)
{
return MemberUtil.MemberName<TType, TResult>(member);
}
}
Then you can use generic type-inference for the return value:
string test1 = MemberUtil<Foo>.MemberName(x => x.Bar);
string test2 = MemberUtil<Foo>.MemberName(x => x.Bloop());
You can write something along this:
static void RegisterMethod<TSelf, TProp> (Expression<Func<TSelf, TProp>> expression)
{
var member_expression = expression.Body as MemberExpression;
if (member_expression == null)
return;
var member = member_expression.Member;
if (member.MemberType != MemberTypes.Property)
return;
var property = member as PropertyInfo;
var name = property.Name;
// ...
}

Categories