help defining a generic method along with expression tree parameter - c#

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

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

Matching an interface's ProperyInfo with a class's PropertyInfo

I use a method similar to the following to get some precomputed metadata related to a Type's properties.
MyData GetProperty<T, U>(Expression<Func<T, U>> member)
{
// Get the property referenced in the lambda expression
MemberExpression expression = member.Body as MemberExpression;
PropertyInfo property = expression.Member as PropertyInfo;
// get the properties in the type T
PropertyInfo[] candidates = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
// Find the match
foreach (PropertyInfo candidate in candidates)
if (candidate == property)
return GetMetaData<T>(candidate);
throw new Exception("Property not found.");
}
// Returns precomputed metadata
MyData GetMetaData<T>(PropertyInfo property) { ... }
As you would expect, it works when used as follows:
var data = PropertyInfo((Employee e) => e.Name);
But not when used in the following generic method:
void MyGenericMethod<T>(int id) where T : IEmployee
{
var data = PropertyInfo((T e) => e.Name);
}
It fails because the declaring type of property in the first method is now IEmployee, so the property in the lambda doesn't match the property in the type. How can I get them to match, without relying on the names of the properties? (There can be multiple properties with the same name if interfaces are implemented explicitly, so p1.Name == p2.Name won't cut it).
What you'd probably need is an InterfaceMapping. You can get that from the actual type by calling GetInterfaceMap(typeof(interface)), i.e.,
InterfaceMapping mapping = typeof(Employee).GetInterfaceMap(typeof(IEmployee));
Now, the mapping will contain the fields InterfaceMethods which will contain the methods you see when reflecting the interface, and TargetMethods which are the class's implementing methods. Note that this maps the the getter methods from the interface to the getter methods from the target class. You'll need to find the proper interface property by mapping the getter method of the various properties of the class to the found getter method.
Type interfaceType = typeof(IEmployee);
Type classType = typeof(Employee);
PropertyInfo nameProperty = interfaceType.GetProperty("Name");
MethodInfo nameGetter = nameProperty.GetGetMethod();
InterfaceMapping mapping = classType.GetInterfaceMap(interfaceType);
MethodInfo targetMethod = null;
for (int i = 0; i < mapping.InterfaceMethods.Length; i++)
{
if (mapping.InterfaceMethods[i] == nameGetter)
{
targetMethod = mapping.TargetMethods[i];
break;
}
}
PropertyInfo targetProperty = null;
foreach (PropertyInfo property in classType.GetProperties(
BindingFlags.Instance | BindingFlags.GetProperty |
BindingFlags.Public | BindingFlags.NonPublic)) // include non-public!
{
if (targetMethod == property.GetGetMethod(true)) // include non-public!
{
targetProperty = property;
break;
}
}
// targetProperty is the actual property
Caution: Note the use of BindingFlags.NonPublic and GetGetMethod(true) here, for accessing private members. If you've got an explicit interface implementation, there isn't really a public property matching the interface's property, instead there is a private property named Some.NameSpace.IEmployee.Name that is mapped (which is, of course, your explicit implementation).
When you've found the right property, you can just call
ParameterExpression p = Expression.Parameter("e", typeof(T));
Expression<Func<T, U>> lambda = Expression.Lambda<Func<T, U>>(
Expression.Property(p, targetProperty), p);
and you've got yourself a lambda expression that uses the class's properties rather than the interface's properties.
Does BindingFlags.FlattenHierarchy work? If not, you could always iterate through typeof(T).GetInterfaces and call GetProperties on each of them.
You'll need to get the member name from the lambda expression, and use reflection to get that member off of the type you've been given:
public static PropertyInfo PropInfo<TContainer, TMember>(
Expression<Func<TContainer, TMember>> memberGetter)
{
var memberName = GetExpressionMemberName(memberGetter);
return typeof(TContainer).GetProperty(memberName);
}
public static string GetExpressionMemberName<TContainer, TMember>(
Expression<Func<TContainer, TMember>> memberGetter)
{
var expressionType = memberGetter.Body.NodeType;
switch (expressionType)
{
case ExpressionType.MemberAccess:
{
var memberExpr = (MemberExpression) memberGetter.Body;
return memberExpr.Member.Name;
}
case ExpressionType.Convert:
{
var convertExpr = (UnaryExpression) memberGetter.Body;
var memberExpr = (MemberExpression) convertExpr.Operand;
return memberExpr.Member.Name;
}
default:
throw new InvalidOperationException("Expression {0} does not represent a simple member access.");
}
}
Here's proof that it works:
void Main()
{
Console.WriteLine(
MyGenericMethod<Employee>()
.GetGetMethod()
.Invoke(
new Employee {Name = "Bill"},
new object[] {}));
}
public class Employee : IEmployee {
public string Name {get;set;}
string IEmployee.Name { get { throw new Exception(); } }
}
public interface IEmployee {string Name {get;}}
public PropertyInfo MyGenericMethod<T>() where T : IEmployee
{
return PropInfo((T e) => e.Name);
}
Console output:
Bill

Get property name and type using lambda expression

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

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