How set value a property selector Expression<Func<T,TResult>> - c#

i need associate a entity property Address in my Person class entity with expressions linq in my FactoryEntities class using pattern factory idea, look this is what I have and I want to do:
Address address = new Address();
address.Country = "Chile";
address.City = "Santiago";
address.ZipCode = "43532";
//Factory instance creation object
//This is idea
Person person = new FactoryEntity<Person>().AssociateWithEntity(p=>p.Address, address);
public class Person: Entity
{
public string Name{ get; set; }
public string LastName{ get; set; }
public Address Address{ get; set; }
}
public class Address: Entity
{
public string Country{ get; set; }
public string City{ get; set; }
public string ZipCode{ get; set; }
}
public class FactoryEntity<TEntity> where TEntity : Entity
{
public void AssociateWithEntity<TProperty>(Expression<Func<TEntity, TProperty>> entityExpression, TProperty newValueEntity) where TProperty : Entity
{
if (instanceEntity == null || instanceEntity.IsTransient())
throw new ArgumentNullException();
/*TODO: Logic the association and validation
How set the newValueEntity into the property of entityExpression (x=>x.Direccion = direccion*/
}
}

This works:
The following helper method converts a getter expression into a setter delegate. If you want to return an Expression<Action<T,TProperty>> instead of an Action<T,TProperty>, just don't call the Compile() method at the end.
Note: The code is from Ian Mercer's blog: http://blog.abodit.com/2011/09/convert-a-property-getter-to-a-setter/
/// <summary>
/// Convert a lambda expression for a getter into a setter
/// </summary>
public static Action<T, TProperty> GetSetter<T, TProperty>(Expression<Func<T, TProperty>> expression)
{
var memberExpression = (MemberExpression)expression.Body;
var property = (PropertyInfo)memberExpression.Member;
var setMethod = property.GetSetMethod();
var parameterT = Expression.Parameter(typeof(T), "x");
var parameterTProperty = Expression.Parameter(typeof(TProperty), "y");
var newExpression =
Expression.Lambda<Action<T, TProperty>>(
Expression.Call(parameterT, setMethod, parameterTProperty),
parameterT,
parameterTProperty
);
return newExpression.Compile();
}

You can set the property like this:
public void AssociateWithEntity<TProperty>(
Expression<Func<TEntity, TProperty>> entityExpression,
TProperty newValueEntity)
where TProperty : Entity
{
if (instanceEntity == null)
throw new ArgumentNullException();
var memberExpression = (MemberExpression)entityExpression.Body;
var property = (PropertyInfo)memberExpression.Member;
property.SetValue(instanceEntity, newValueEntity, null);
}
This will work only for properties, not fields, although adding support for fields should be easy.
But the code you have for getting the person won't work. If you want to keep the void return type of AssociateWithEntity(), you could do it like this:
var factory = new FactoryEntity<Person>();
factory.AssociateWithEntity(p => p.Address, address);
Person person = factory.InstanceEntity;
Another option is a fluent interface:
Person person = new FactoryEntity<Person>()
.AssociateWithEntity(p => p.Address, address)
.InstanceEntity;

Another solution is to get the property owner and invoke the property setter using reflection. The advantage of this solution is that it does not use extension methods and can be called with any type.
private void SetPropertyValue(Expression<Func<object, object>> lambda, object value)
{
var memberExpression = (MemberExpression)lambda.Body;
var propertyInfo = (PropertyInfo)memberExpression.Member;
var propertyOwnerExpression = (MemberExpression)memberExpression.Expression;
var propertyOwner = Expression.Lambda(propertyOwnerExpression).Compile().DynamicInvoke();
propertyInfo.SetValue(propertyOwner, value, null);
}
...
SetPropertyValue(s => myStuff.MyPropy, newValue);

This is my solution that uses Expression.Assign, but after looking more closely, the accepted answer is just as good.
// optionally or additionally put in a class<T> to capture the object type once
// and then you don't have to repeat it if you have a lot of properties
public Action<T, TProperty> GetSetter<T, TProperty>(
Expression<Func<T, TProperty>> pExpression
) {
var parameter1 = Expression.Parameter(typeof(T));
var parameter2 = Expression.Parameter(typeof(TProperty));
// turning an expression body into a PropertyInfo is common enough
// that it's a good idea to extract this to a reusable method
var member = (MemberExpression)pExpression.Body;
var propertyInfo = (PropertyInfo)member.Member;
// use the PropertyInfo to make a property expression
// for the first parameter (the object)
var property = Expression.Property(parameter1, propertyInfo);
// assignment expression that assigns the second parameter (value) to the property
var assignment = Expression.Assign(property, parameter2);
// then just build the lambda, which takes 2 parameters, and has the assignment
// expression for its body
var setter = Expression.Lambda<Action<T, TProperty>>(
assignment,
parameter1,
parameter2
);
return setter.Compile();
}
Another thing you can do is encapsulate them:
public sealed class StrongProperty<TObject, TProperty> {
readonly PropertyInfo mPropertyInfo;
public string Name => mPropertyInfo.Name;
public Func<TObject, TProperty> Get { get; }
public Action<TObject, TProperty> Set { get; }
// maybe other useful properties
internal StrongProperty(
PropertyInfo pPropertyInfo,
Func<TObject, TProperty> pGet,
Action<TObject, TProperty> pSet
) {
mPropertyInfo = pPropertyInfo;
Get = pGet;
Set = pSet;
}
}
And now you can pass these around, similar to delegates, and write code whose logic can vary by property. This gets around the fact that you can't pass properties by reference.

That's the idea, i'm worked for me with this code, taking into account the contribution of svick:
public class FactoryEntity<TEntity> where TEntity : Entity, new()
{
private TEntity _Entity;
public FactoryEntity()
{
_Entity = new TEntity();
}
public TEntity Build()
{
if (_Entity.IsValid())
throw new Exception("_Entity.Id");
return _Entity;
}
public FactoryEntity<TEntity> AssociateWithEntity<TProperty>(Expression<Func<TEntity, TProperty>> foreignEntity, TProperty instanceEntity) where TProperty : Entity
{
if (instanceEntity == null || instanceEntity.IsTransient())
throw new ArgumentNullException();
SetObjectValue<TEntity, TProperty>(_Entity, foreignEntity, instanceEntity);
return this;
}
private void SetObjectValue<T, TResult>(object target, Expression<Func<T, TResult>> expression, TResult value)
{
var memberExpression = (MemberExpression)expression.Body;
var propertyInfo = (PropertyInfo)memberExpression.Member;
var newValue = Convert.ChangeType(value, value.GetType());
propertyInfo.SetValue(target, newValue, null);
}
}
Here I call the factory for me to build the Person object in a valid
Person person = new FactoryEntity<Person>().AssociateWithEntity(p=>p.Address, address).Build();
But I do not know if this code is optimal or not, at least I do not make a call to compile() method, what are saying?
thanks

I've made mixed Rytis I solution and https://stackoverflow.com/a/12423256/254109
private static void SetPropertyValue<T>(Expression<Func<T>> lambda, object value)
{
var memberExpression = (MemberExpression)lambda.Body;
var propertyInfo = (PropertyInfo)memberExpression.Member;
var propertyOwnerExpression = (MemberExpression)memberExpression.Expression;
var propertyOwner = Expression.Lambda(propertyOwnerExpression).Compile().DynamicInvoke();
propertyInfo.SetValue(propertyOwner, value, null);
}
And call it
SetPropertyValue(() => myStuff.MyProp, newValue);

Everything is much simpler:
public static Action<T, TValue> GetSetter<T, TValue>(
Expression<Func<T, TValue>> expression)
{
var parameter = Expression.Parameter(typeof(TValue), "value");
var setterLambda = Expression.Lambda<Action<T, TValue>>(
Expression.Assign(expression.Body, parameter),
expression.Parameters[0],
parameter);
return setterLambda.Compile();
}

Related

Write extension method to retrieve property description using c#

I have following class
public class Device
{
[XmlElement("MobileDeviceType")]
public string DeviceType { get; set; }
}
I need extension method called "GetXElementName()" and I need to use the method like below.
string propertyDescription = (new Device()).DeviceType.GetXElementName(); // this shoud return "MobileDeviceType"
As a example
public static class ExtensionMethods
{
public static string GetXElementName<T>(this T source)
{
PropertyInfo prop = source.GetType().GetProperty(source.ToString());
string desc = prop.Name;
object[] attrs = prop.GetCustomAttributes(true);
object attr = attrs[0];
XmlElementAttribute descAttr = attr as XmlElementAttribute;
if (descAttr != null)
{
desc = descAttr.ElementName;
}
return desc;
}
}
Can I know how should I modify the method body to use the "GetXElementName()" method to use like I explained above.
You need to use Expressions to achieve that, because you need to know the member, not the value.
public static class Extensions
{
public static string GetXmlElementName<T, TProperty>(this T obj, Expression<Func<T, TProperty>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
return string.Empty;
var xmlElementAttribute = memberExpression.Member.GetCustomAttribute<XmlElementAttribute>();
if (xmlElementAttribute == null)
return string.Empty;
return xmlElementAttribute.ElementName;
}
}
Usage:
public class MyClass
{
[XmlElement(ElementName = "Test")]
public string MyProperty { get; set; }
}
new MyClass().GetXmlElementName(x => x.MyProperty) // output "Test"
EDIT: another version, without an object instance (see Nyerguds comment)
I guess the most elegant way is make a generic class, with a generic method, so you can call it by specify only the T type parameter (TProperty is taken implicitly).
public class GetXmlElementName<T>
{
public static string From<TProperty>(Expression<Func<T, TProperty>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
return string.Empty;
var xmlElementAttribute = memberExpression.Member.GetCustomAttribute<XmlElementAttribute>();
if (xmlElementAttribute == null)
return string.Empty;
return xmlElementAttribute.ElementName;
}
}
Usage:
GetXmlElementName<MyClass>.From(x => x.MyProperty) // output "Test"

Create Expression Tree dynamically

I had an idea and want to know if it can work.
I have a simple classes with properties and want to generate accessors with Expressions.
But in the end I need to get a Func<Test, string> but I don't know the types when I use them.
A small example
class Program
{
static void Main(string[] args)
{
Test test = new Test();
test.TestString = "Blubb";
var actionStub = typeof(Helper).GetMethod("CreatePropertyGetter").MakeGenericMethod(new Type[] { test.GetType(), typeof(string)});
dynamic action = actionStub.Invoke(null, new object[] {test.GetType(), "TestString"});
var x = action(test);
}
}
public class Test
{
public string TestString { get; set; }
}
public static class Helper
{
public static Func<TType, TPropValueType> CreatePropertyGetter<TType, TPropValueType>(Type type,
string propertyName)
{
PropertyInfo fieldInfo = type.GetProperty(propertyName);
ParameterExpression targetExp = Expression.Parameter(typeof(TType), "target");
MemberExpression fieldExp = Expression.Property(targetExp, fieldInfo);
UnaryExpression assignExp = Expression.Convert(fieldExp, typeof(TPropValueType));
Func<TType, TPropValueType> getter =
Expression.Lambda<Func<TType, TPropValueType>>(assignExp, targetExp).Compile();
return getter;
}
}
The problem is I cant call the expression without dynamic, because I cant simple cast it to Func<object, object>
You're generating (TType target) => target.Something. Instead, generate (object target) => (object)((TType)target).Something so that you can use Func<object, object>.
It's not clear what exactly you are asking for, but here is an example how you can make it Func<object, object>:
public static class Helper
{
public static Func<object, object> CreatePropertyGetter(Type type, string propertyName)
{
var fieldInfo = type.GetProperty(propertyName);
var targetExp = Expression.Parameter(typeof(object), "target");
var fieldExp = Expression.Property(Expression.ConvertChecked(targetExp, type), fieldInfo);
var getter = Expression.Lambda<Func<object, object>>(fieldExp,targetExp).Compile();
return getter;
}
}

Property set method not found (expression, audited entity)

I'm running into a System.ArgumentException with the message Property set method not found. when I try to set a value using reflection with the following statement:
propertyInfo.SetValue(instance, newValue,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null,
null, null);
This question on SO indicates that the problem arises because of inheritance, however I'm not able to figure out how I could get around it with my current code.
What I'm basically trying to do is setting a creation date on a audited entity using NHibernate. For this, I got the following set up (warning, wall of code!):
IEntity
public interface IEntity<TKey> : IEquatable<IEntity<TKey>>
{
TKey Id { get; }
bool IsTransient { get; }
TKey GetDefaultId();
}
EntityBase
public abstract class EntityBase<TKey> : IEntity<TKey>
{
// omitted for brevity
}
IHasCreationTime
public interface IHasCreationTime {
DateTime CreationTime { get; }
}
ICreationAudited
public interface ICreationAudited : IHasCreationTime {
string CreatorId { get; }
}
TestEntity
public class TestEntity : EntityBase<int>, ICreationAudited {
public string Name { get; set; }
public string CreatorId { get; set; }
public DateTime CreationTime { get; set; }
}
NHibernateAuditInterceptor
internal class NHibernateAuditInterceptor : EmptyInterceptor {
public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
var auditable = entity as ICreationAudited;
if(auditable == null)
return false;
auditable.SetProperty(x => x.CreationTime, DateTime.UtcNow);
return true;
}
}
SetProperty extension
public static void SetProperty<T, TProperty>(this T instance, Expression<Func<T, TProperty>> selector, TProperty newValue)
where T: class
{
var propertyInfo = selector.GetMember() as PropertyInfo;
propertyInfo.SetValue(instance, newValue, BindingFlags.Public // nonpublic etc..
}
GetMember extension
public static MemberInfo GetMember<T, TProperty>(this Expression<Func<T, TProperty>> expression)
{
var memberExp = RemoveUnary(expression.Body);
return memberExp == null ? null : memberExp.Member;
}
RemoveUnary extension
private static MemberExpression RemoveUnary(Expression toUnwrap)
{
var unwrap = toUnwrap as UnaryExpression;
if (unwrap != null)
{
return unwrap.Operand as MemberExpression;
}
return toUnwrap as MemberExpression;
}
What changes could I make to overcome this?
Your SetProperty extension method will not compile because of this expression...
var selector.GetMember() as PropertyInfo;
which is not a valid assignment statement in C#. I will assume that you actually meant to say...
var propertyInfo = selector.GetMember() as PropertyInfo;
If that is the case, the reason why you might be getting an System.ArgumentException is because the lambda your passing in has no idea what the actual type is, it only knows about its contract (the interface), however, the reflection method you're using only works with concrete types. To get your SetProperty extension method to work you will need to use the actual concrete class as below...
public static void SetProperty<T, TProperty>(this T instance, Expression<Func<T, TProperty>> selector, TProperty newValue)
where T : class
{
var propertyInfo = selector.GetMember() as PropertyInfo;
instance.GetType().GetProperty(propertyInfo.Name).SetValue(instance, newValue, null);
}
that will work

LINQ to Entities does not recognize the method 'System.Object GetValue(...)'

My issue is I need to query on the value of a property in a generic class. The property is tagged with an attribute.
See the following code:
var rowKeyProperty = EFUtil.GetClassPropertyForRowKey<T>();
var tenantKeyProperty = EFUtil.GetClassPropertyForTenantKey<T>();
var queryResult =
objContext.CreateObjectSet<T>().Single(l => (((int) tenantKeyProperty.GetValue(l, null)) == tenantKey) &&
(((int)rowKeyProperty.GetValue(l, null)) == KeyValue));
The rowKeyProperty and tenantKeyProperty are of type System.Reflection.PropertyInfo.
I understand why I am getting the error. When the linq query is translated to SQL, it can't understand the property.GetValue.
However, I'm completely stumped as to a work around here. Does anyone have any ideas how to achieve this? Thx.
You need to actually build up the Expression objects to represent the expression that you want this to mimic, in this case the expression you want to represent is:
l => l.SomeProperty == SomeValue
So you need to build up each component of that bit by bit, from creating the parameter, defining the equality operator, the property access, the constant value, etc.
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(
PropertyInfo property, TValue value)
{
var param = Expression.Parameter(typeof(TItem));
var body = Expression.Equal(Expression.Property(param, property),
Expression.Constant(value));
return Expression.Lambda<Func<TItem, bool>>(body, param);
}
Once you have all of that you can call it using the data that you have:
var queryResult = objContext.CreateObjectSet<T>()
.Where(PropertyEquals<T, int>(tenantKeyProperty, tenantKey))
.Where(PropertyEquals<T, int>(rowKeyProperty, KeyValue))
.Single();
Appendix here... Following #Servy answer and based on this topic with a nice answer by #TomBrothers, you can use the same logic to make a StartsWith (or similar) function:
public static Expression<Func<TItem, bool>> PropertyStartsWith<TItem>(PropertyInfo propertyInfo, string value)
{
var param = Expression.Parameter(typeof(TItem));
var m = Expression.MakeMemberAccess(param, propertyInfo);
var c = Expression.Constant(value, typeof(string));
var mi = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
var body = Expression.Call(m, mi, c);
return Expression.Lambda<Func<TItem, bool>>(body, param);
}
In this case, it forces value to be a string.
It is more correct to specify the type in Expression.Constant(value, typeof(TValue)))
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(
string property, TValue value)
{
var xParameter = Expression.Parameter(typeof(TItem));
var body = Expression.Equal(Expression.Property(xParameter, property), Expression.Constant(value, typeof(TValue)));
return Expression.Lambda<Func<TItem, bool>>(body, xParameter);
}
Or, like this, to check the property. ChangeType
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(
string property, TValue value)
{
var xParameter = Expression.Parameter(typeof(TItem));
var type = typeof(TItem).GetProperty(property).PropertyType;
value = ChangeType<TValue>(value);
BinaryExpression body = Expression.Equal(Expression.Property(xParameter, property), Expression.Constant(value, type));
return Expression.Lambda<Func<TItem, bool>>(body, xParameter);
}
What is it for. I check all class references to classes, I look for "..ID" entries. Somewhere I have a type "int" and "int?".
public class BudgetLimit : BaseRecord
{
[Required]
public int DepartmentID { get; set; }
public virtual Department Department { get; set;}
public int? ProjectID { get; set; }
public virtual Project Project { get; set; }
}
You add .AsEnableable after the LINQ statement.
e.g objectdata.AsEnumerable()
enter link description here

How can I pass a property in via a lambda expression?

There are some unit tests on my project where we want to be able to set some properties that have private setters. Currently I'm doing it via reflection and this extension method:
public static void SetPrivateProperty(this object sourceObject, string propertyName, object propertyValue)
{
sourceObject.GetType().GetProperty(propertyName).SetValue(sourceObject, propertyValue, null);
}
Assuming I had a TestObject like this:
public class TestObject
{
public int TestProperty{ get; private set; }
}
I can then call this in my unit tests as follows:
myTestObject.SetPrivateProperty("TestProperty", 1);
However, I'd like to have validation of the property name at compile time, and thus I'd like to be able to pass the property in via expression, like this:
myTestObject.SetPrivateProperty(o => o.TestProperty, 1);
How can I do this?
If the getter is public, then the following should work. It will give you an extension method that looks like this:
var propertyName = myTestObject.NameOf(o => o.TestProperty);
It requires a public getter. I hope, at some point, reflection functionality like this is rolled into the language.
public static class Name
{
public static string Of(LambdaExpression selector)
{
if (selector == null) throw new ArgumentNullException("selector");
var mexp = selector.Body as MemberExpression;
if (mexp == null)
{
var uexp = (selector.Body as UnaryExpression);
if (uexp == null)
throw new TargetException(
"Cannot determine the name of a member using an expression because the expression provided cannot be converted to a '" +
typeof(UnaryExpression).Name + "'."
);
mexp = uexp.Operand as MemberExpression;
}
if (mexp == null) throw new TargetException(
"Cannot determine the name of a member using an expression because the expression provided cannot be converted to a '" +
typeof(MemberExpression).Name + "'."
);
return mexp.Member.Name;
}
public static string Of<TSource>(Expression<Func<TSource, object>> selector)
{
return Of<TSource, object>(selector);
}
public static string Of<TSource, TResult>(Expression<Func<TSource, TResult>> selector)
{
return Of(selector as LambdaExpression);
}
}
public static class NameExtensions
{
public static string NameOf<TSource, TResult>(this TSource obj, Expression<Func<TSource, TResult>> selector)
{
return Name.Of(selector);
}
}
New to C# 6.0 : nameof(property)

Categories

Resources