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)
Related
This question already has answers here:
How can I get the name of a variable passed into a function?
(23 answers)
Closed 7 years ago.
Is it possible to create a function that returns the name of variable like .ToString() return the string value of a variable.
static class myExten
{
public static string ToName(this object o)
{
///some code that returns the name
}
}
static void Main()
{
string country = "India";
string variableName = country.ToName();
}
Many thanks for your attention.
Edit
As my question is being marked duplicate, I am trying to explain how my qestion is diffrent
I have a generic function that returns a bool value(given below)
static public bool stateNameExists(string name)
{
return SQL_Functions.AlreadyExists("**state_name**", table, name);
}
public static bool AlreadyExists(string column, string table, string value)
{
string qry = "select count(" + column + ") from " + table + " where " + column + " = '"+value+"'";
string result = execute_scaller(qry);
try
{
if (Convert.ToInt16(result) > 0)
{
return true;
}
}
catch
{
return false;
}
return false;
}
Please pay attention at stateNameExists function. In this function I am hardcoding the column name "state_name"
I have a model class
class stateModel
{
public int id [get; set;}
public string state_name {get; set;}
}
I want to pass the name of column using model object like this
SQL_Functions.AlreadyExists(obj.state_name.GetName(), table, name);
that's why I asked for an extension function.
P.S: I can not use c# 6.0 tricks here.
Note: If the question is still duplicate/already answered then please provide its link. Many and Many thanks.
If I get you right, you would need to do something like this:
PropertyHelper.GetName<stateModel>(x=>x.state_name)
and receive stringified name of property here: "state_name".
We use a property helper class for getting property names, you can try this implementation:
public class PropertyHelper
{
public static string GetName<T>(Expression<Func<T>> expression)
{
return GetName(expression.Body);
}
public static string GetName<T>(Expression<Func<T, object>> expression)
{
return GetName(expression.Body);
}
public static string GetName<T, TProperty>(Expression<Func<T, TProperty>> expression)
{
return GetName(expression.Body);
}
public static Type GetType<T>(Expression<Func<T, object>> expression)
{
return GetMemberExpression(expression.Body).Type;
}
public static Type GetType<T, TProperty>(Expression<Func<T, TProperty>> expression)
{
return GetMemberExpression(expression.Body).Type;
}
private static MemberExpression GetMemberExpression(Expression expression)
{
var getMemberExpression = expression as MemberExpression;
if (getMemberExpression != null)
return getMemberExpression;
if (IsConversion(expression))
{
var unaryExpression = expression as UnaryExpression;
if (unaryExpression != null)
return GetMemberExpression(unaryExpression.Operand);
}
return null;
}
private static string GetName(Expression expression)
{
return string.Join(".", GetNames(expression));
}
private static IEnumerable<string> GetNames(Expression expression)
{
var memberExpression = GetMemberExpression(expression);
if (memberExpression == null)
yield break;
foreach (var memberName in GetNames(memberExpression.Expression))
yield return memberName;
yield return memberExpression.Member.Name;
}
private static bool IsConversion(Expression expression)
{
return (expression.NodeType == ExpressionType.Convert
|| expression.NodeType == ExpressionType.ConvertChecked);
}
}
in c# 6, you can use nameof operator, but not within an extension method
static class myExten
{
public static string ToName(this object o)
{
return nameof(o);
}
}
this will always returns "o", i.e. the name of the variable in this method
the best you can do is something such:
static void Main()
{
string country = "India";
string variableName = nameof(country);
}
I have a common problem, that I am trying to get round in a specific way.
Basically with Winforms, I am trying to set the "DisplayMember" and "ValueMember" of controls in a form. You would normally set it like so:
this.testCombobox.DisplayMember = "PropertyOne";
this.testCombobox.ValueMember = "PropertyTwo";
I want to rewrite this as follows:
this.testCombobox.DisplayMember = ClassOne.GetPropertyName(c => c.PropertyOne);
this.testCombobox.ValueMember = ClassOne.GetPropertyName(c => c.PropertyTwo);
(NOTE: the 2 method calls need to be static, to save creating objects here)
All of my classes that I am trying to do this, inherit from a base class "BaseObject", so I have added a method to it as follows:
public static string GetPropertyName<T, P>(Expression<Func<T, P>> action) where T : class
{
MemberExpression expression = action.Body as MemberExpression;
return expression.Member.Name;
}
However, in order to use this, I need to write the following code instead:
this.testCombobox.DisplayMember = BaseObject.GetPropertyName((ClassOne c) => c.PropertyOne);
My question is, how would I rewrite the method BaseObject.GetPropertyName to achieve what I want? I feel I am very close but cannot think how to change it.
Your current GetPropertyName method leaves open the generic T. Hence, the compiler cannot resolve it compile-time since you do not specify it when you use the method.
However, if you make your base class generic, AND specify the T in the derived class, AND specify to use the method of the derived class (and not the base class), then it works.
Like this:
public class BaseClass<T> {
public static string GetPropertyName<P>(Expression<Func<T, P>> action) {
MemberExpression expression = action.Body as MemberExpression;
return expression.Member.Name;
}
}
public class ClassOne : BaseClass<ClassOne> {
public string PropertyOne { get; set; }
}
public static class Test {
public static void test() {
var displayMember = ClassOne.GetPropertyName(x => x.PropertyOne);
}
}
I created a Helper class to extract Proprty Name
public 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("Invalide Expression", "propertyExpression");
}
return memberExpression.Member.Name;
}
}
And you can use it as Follows :
PropertySupport.ExtractPropertyName(() => DateTime.Now)
it will return "Now"
EDIT
Here is a test console app:
public 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");
}
return memberExpression.Member.Name;
}
}
public class MyClass
{
public MyClass PropertyOne { get; set; }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(PropertySupport.ExtractPropertyName(() => new MyClass().PropertyOne));
Console.ReadKey();
}
}
I would suggest the following in generic helper:
public static class GenericHelper<TEntity> {
public static string GetPropertyName<TProperty>(Expression<Func<TEntity, TProperty>> propertyExpression) {
return propertyExpression.GetPropertyName();
}
}
and the following in Extensions for common usage:
public static class ReflectionExtensions {
public static PropertyInfo GetProperty<TEntity, TProperty>(this Expression<Func<TEntity, TProperty>> source) {
//TODO: check TEntity, if needed. Now it's ignored
var member = source.Body as MemberExpression;
if (member == null) {
throw new ArgumentException(String.Format(
"Expression '{0}' refers to a method, not a property.", source));
}
var propertyInfo = member.Member as PropertyInfo;
if (propertyInfo == null) {
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.", source));
}
return propertyInfo;
}
public static string GetPropertyName<TEntity, TProperty>(this Expression<Func<TEntity, TProperty>> source) {
return source.GetProperty().Name;
}
}
I want to check custom attributes on my class members (fields only) by using an extension method.
public class DatabaseIdAttribute : Attribute
{
public int ID { get; set; }
public DatabaseIdAttribute(int id)
{
this.ID = id;
}
}
public class MyClass
{
[DatabaseId(1)]
double Height {get;set;}
[DatabaseId(2)]
double Width {get;set;}
double Area { get { return this.Height * this.Width; }
}
I want to use LINQ expression in the extension method to access the class field instead of passing magic strings.
var myClass = new MyClass();
var attribute = myClass.GetAttribute<DatabaseIdAttribute>(c => c.Height);
Is it possible to achieve?
[EDIT]
For the time being, I have achieved the following with the help of #leppie
public static MemberInfo GetMember<T, R>(this T instance, Expression<Func<T, R>> selector)
{
var member = selector.Body as MemberExpression;
if (member != null)
{
return member.Member;
}
return null;
}
public static T GetAttribute<T>(this MemberInfo member) where T : Attribute
{
return member.GetCustomAttributes(false).OfType<T>().SingleOrDefault();
}
which enables to get the attribute in the following way
var c = new MyClass();
var attribute = c.GetMember(m => m.Height).GetAttribute<DatabaseIdAttribute>();
but I want to be able to access it in the following way
var c = new MyClass();
var attribute = c.GetAttribute<DatabaseIdAttribute>(m => m.Height);
You are almost there! This should work (untested).
public static class ObjectExtensions
{
public static MemberInfo GetMember<T,R>(this T instance,
Expression<Func<T, R>> selector)
{
var member = selector.Body as MemberExpression;
if (member != null)
{
return member.Member;
}
return null;
}
// unnecessary in .NET 4.5 and up, see note!
public static T GetAttribute<T>(this MemberInfo meminfo) where T : Attribute
{
return meminfo.GetCustomAttributes(typeof(T)).FirstOrDefault() as T;
}
}
Usage:
var attr = someobject.GetMember(x => x.Height).
GetAttribute<DatabaseIdAttribute>();
Note: As of .NET 4.5 and up (including .NET Core), the BCL provides a GetCustomAttribute<T>(MemberInfo) extension method that functions identically to the GetAttribute method defined above, and should be used instead if available.
If you don't mind supplying the extra generic types, you can do this:
public static class ReflectionHelper
{
public static TAttr GetAttribute<TClass, TProp, TAttr>(Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
{
var member = selector.Body as MemberExpression;
return member.Member.GetCustomAttributes<TAttr>(false).First();
}
}
Then you can use it like this:
var attribute = ReflectionHelper.GetAttribute<MyClass, double, DatabaseIdAttribute>(m => m.Height);
Note that this is not an extension method (as we can't have static extensions) so there is no need to create an instance of your class.
Of course you could still have the extension method version:
public static TAttr GetAttribute<TClass, TProp, TAttr>(this TClass instance, Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
{
var member = selector.Body as MemberExpression;
return member.Member.GetCustomAttributes<TAttr>(false).First();
}
Which would let you call it like so:
var c = new MyClass();
var attribute = c.GetAttribute<MyClass, double, DatabaseIdAttribute>(m => m.Height);
But either way is quite verbose. If you want the compile to infer all of the generic types, we'd need to pass in an instance of our attribute:
public static class ReflectionHelper
{
public static TAttr GetAttribute<TClass, TProp, TAttr>(TAttr attribute, Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
{
var member = selector.Body as MemberExpression;
return member.Member.GetCustomAttributes<TAttr>(false).First();
}
}
Usage:
var attribute = ReflectionHelper.GetAttribute(new DatabaseIdAttribute(), m => m.Height);
I want to make a cloning or mapping function where I can specify (once) which properties to copy to the target object.
The whole point here was a usage that looks something like this
(inspired by using GroupBy),
var botchedOrder = db.BuildingOrders.Find(id);
var redo = db.BuildingOrders.Create();
botchedOrder.MapTo(redo, x => new { x.BasePrice, x.FileAttachments, x.Notes });
This is over my head, but I was guessing at something like this,
public static void MapTo<TObject, TProps>(
this TObject source,
TObject target,
Action<TProps> properties) //?
{
//copy the defined properties from source to target somehow?
//originally I thought I could make an array of delegates..
}
If this works then I can more easily handle different sets of properties in different ways when I am explicitly cloning or mapping objects. I'd like to stick w/ .NET to do this.
EDIT: forgot to indicate void
I'd recommend looking at AutoMapper since it kind of solves same kinds of problems. Also, different ORM sources (like Massive, Petapoco etc.) all have some implementations (since they need to map data from a DB to an object).
Basically, it works either using reflection - to iterate over given fields/properties and set them to another object (also via refleciton). There are approaches to dynamic method generation using IL Generator or Expression Trees that wrap all the reflection code into one nice and fast method generated and compiled at runtime (thus giving performance boost).
Another way to do would be using dynamics or Dictionaries instead of anonymous class - that would remove "anonimity" problem and would just require to map specific keys on to properties - may be done with reflection again (using for example [MappingAttribute("Key")] for distinction - attribute is a fiction, just to give a general idea).
This is the most succinct form I can think of without dropping down to reflection, but it does involve repeating property names, so I'm not sure if it's exactly what you want.
public static void MapTo<TObject>(this TObject source, TObject target, params Action<TObject, TObject>[] properties)
{
foreach (var property in properties)
{
property(source, target);
}
}
Called like:
void Copy(FooBar source, FooBar target)
{
source.MapTo(target, (s,t) => t.Foo = s.Foo,
(s,t) => t.Bar = s.Bar,
(t,s) => t.Baz = s.Baz);
}
class FooBar
{
public string Foo { get; set; }
public string Bar { get; set; }
public string Baz { get; set; }
}
However, it's more verbose that just doing:
void Copy(FooBar source, FooBar target)
{
target.Foo = source.Foo;
target.Bar = source.Bar;
target.Baz = source.Baz;
}
Is there anything else going on in your copy that make the last example invalid? If not, I would just keep it simple and go for that.
Here is a basic dynamic mapper I wrote. I used a slightly different approach as I extended object and instead of specifying the properties, used ignore properties.
public static class ObjectExtensions
{
public static void CopyFrom(this object Instance, object Source)
{
ObjectExtensions.CopyFrom(Instance, Source, false, null);
}
public static void CopyFrom(this object Instance,
object Source,
IEnumerable<string> IgnoreProperties)
{
ObjectExtensions.CopyFrom(Instance, Source, false, IgnoreProperties);
}
public static void CopyFrom(this object Instance,
object Source,
bool ThrowOnPropertyMismatch,
IEnumerable<string> IgnoreProperties)
{
Type sourceType = Source.GetType();
BindingFlags publicInstanceFlags = BindingFlags.Public
| BindingFlags.Instance;
PropertyInfo[] sourceProperties =
sourceType.GetProperties(publicInstanceFlags);
Type instanceType = Instance.GetType();
foreach (PropertyInfo sourceProperty in sourceProperties)
{
if (IgnoreProperties == null
|| (IgnoreProperties.Count() > 0
&& !IgnoreProperties.Contains(sourceProperty.Name)))
{
PropertyInfo instanceProperty =
instanceType.GetProperty(sourceProperty.Name, publicInstanceFlags);
if (instanceProperty != null
&& instanceProperty.PropertyType == sourceProperty.PropertyType
&& instanceProperty.GetSetMethod() != null
&& instanceProperty.GetSetMethod().IsPublic)
{
instanceProperty.SetValue(Instance,
sourceProperty.GetValue(Source, null),
null);
}
else
if (ThrowOnPropertyMismatch
&& instanceProperty.PropertyType != sourceProperty.PropertyType)
{
throw new InvalidCastException(
string.Format("Unable to cast source {0}.{1} to destination {2}.{3}.",
Source.GetType().Name,
sourceProperty.Name,
Instance.GetType().Name,
instanceProperty.Name));
}
}
}
}
A common way of doing this is by using expression trees which can represent the way certain types should map to one another. A primitive stripped down example of such is:
public static void MapTo<TInput, TOutput>(this TInput input, TOutput output, Expression<Func<TInput, TOutput, bool>> expression)
where TInput : class
where TOutput : class
{
if (expression == null)
throw new ArgumentNullException("expression");
Stack<Expression> unhandeledExpressions = new Stack<Expression>();
unhandeledExpressions.Push(expression.Body);
while (unhandeledExpressions.Any())
{
Expression unhandeledExpression = unhandeledExpressions.Pop();
switch (unhandeledExpression.NodeType)
{
case ExpressionType.AndAlso:
{
BinaryExpression binaryExpression = (BinaryExpression)unhandeledExpression;
unhandeledExpressions.Push(binaryExpression.Left);
unhandeledExpressions.Push(binaryExpression.Right);
}
break;
case ExpressionType.Equal:
{
BinaryExpression binaryExpression = (BinaryExpression)unhandeledExpression;
MemberExpression leftArgumentExpression = binaryExpression.Left as MemberExpression;
MemberExpression rightArgumentExpression = binaryExpression.Right as MemberExpression;
if (leftArgumentExpression == null || rightArgumentExpression == null)
throw new InvalidOperationException("Can only map to member expressions");
output.GetType().GetProperty(leftArgumentExpression.Member.Name).SetValue(
output, input.GetType().GetProperty(rightArgumentExpression.Member.Name).GetValue(input, null), null);
}
break;
default:
throw new InvalidOperationException("Expression type not supported");
}
}
}
}
which can be used in the following way:
class SourceType
{
public string Name { get; set; }
public int Number { get; set; }
}
class DestinationType
{
public string CustName { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
var source = new SourceType()
{
Name = "Test",
Number = 22
};
var destination = new DestinationType();
source.MapTo(destination, (src, dst) => dst.CustName == src.Name && dst.Age == src.Number);
bool assert = source.Name == destination.CustName && source.Number == destination.Age;
}
}
The advantage of this approach is that this allows you to define your own mapping 'language' which you can make as complex/extensive as you want.
Still I recommend you to use a pre-built solution like AutoFaq or AutoMapper. Good luck
ok, I think I have something working using an Expression and Reflection.
thing1.MapTo(thing2, x => new { x.Prop1, x.Prop2 });
and
public static void MapTo<T, P>(
this T source, T target, Expression<Func<T, P>> expr)
{
(expr.Body as NewExpression).Members.ToList()
.ForEach(m => source.Copy(target, m.Name));
}
public static void Copy<T>(this T source, T target, string prop)
{
var p = typeof(T).GetProperty(prop);
p.SetValue(target, p.GetValue(source, null), null);
}
I'm not sure the methods have the best names but it's a start and it allows the usage I was hoping for. Any problems with this approach?
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();
}