Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C# Trees
It appears that I need to pass an Expression Tree to a method to be able to get its name, but i also want to set the value also, is there a way to do that:
 
  name = Method(() => property, value);
 
  public string Method<T>(Expression<Func<T>> property, T value)
  {
    var propertyName = GetPropertyString(property);
    // Here I want to set the property to the value
    //i.e., property = value;
    return propertyName;
  }
 
Thanks
 
Note: The solutions using reflection would work well, except that the method is in the base class and the properties are in a derived class, so that would have to pass the a reference to the derived class in order for solution to work. I was hopeing there was some way to use the property information to set the value. It would be just as clean to send the property reference in the Expression Tree information. Anybody understand expresson trees well enough?
Posted 10-Feb-12 6:43am
Edited 10-Feb-12 9:52am
v6
Comments
Andreas Gieriet at 10-Feb-12 11:53am
   
You Code seems incomplete above. Please edit to have a complete code example above (use &lt; and &gt; to encode < and >).
 
To your questions: it seems odd to me that you want to pass a property (of which you must know the name) and want to get back that exact name again (?).
 
Why not simply do property = value; string name = "property";
 
Or am I missing something here?
 
Cheers
 
Andi
Clifford Nelson at 10-Feb-12 12:07pm
   
Thanks for that. The reason for not using a string is that like all strings, it is a maintenance issue if property name is ever changed.
Andreas Gieriet at 10-Feb-12 12:16pm
   
I've put your code into a <pre lang="cs">...</pre> block.
 
Andi
Wonde Tadesse at 11-Feb-12 11:17am
   
Please see the solution below. It is quite perfect.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

If you are willing to pay a permanent runtime penalty for your argument of maintainability, you could do it via reflection. You would also lose type savety.
 
private static void SetStatic<T>(string prop, T value)
{
    var p = MethodInfo.GetCurrentMethod().DeclaringType.GetProperty(prop);
    p.SetValue(null, value, null);
}
private void Set<T>(string prop, T value)
{
    var p = MethodInfo.GetCurrentMethod().DeclaringType.GetProperty(prop);
    p.SetValue(this, value, null);
}
 
public static int StaticProp { get; set; }
public int Prop { get; set; }
 
static void Main(string[] args)
{
    SetStatic("StaticProp", 7);
    var obj = new Program();
    obj.Set("Prop", 123);
}
 
I doubt if this is a reasonable scenario - properties do not change often enough to justify this overhead.
 
Just my 5 cents.
 
Cheers
 
Andi
  Permalink  
Comments
Clifford Nelson at 10-Feb-12 15:06pm
   
Thanks for the input. As stated above, reflection would not be the best. Will see what the performance penalty is on this however.
Clifford Nelson at 10-Feb-12 16:53pm
   
The idea would not have worked for my needs anyway, and there was a significant performance hit.
 
Thanks
BillWoodruff at 10-Feb-12 18:54pm
   
+5 !
Andreas Gieriet at 10-Feb-12 19:48pm
   
Thanks for your 5, BillWoodruff!
Wonde Tadesse at 11-Feb-12 11:16am
   
5+
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

Or an alternative of Solution #1 to play around a bit Wink | ;-)
 
public static int StaticProp { get; set; }
public int Prop { get; set; }
 
private static string StaticSet<T>(Expression<Func<T>> p, T v)
{
    string name = p.Body.ToString().Split('.', '+', '/').Last();
    MethodInfo.GetCurrentMethod().DeclaringType.GetProperty(name).SetValue(null, v, null);
    return name;
}
private string Set<T>(Expression<Func<T>> p, T v)
{
    string name = p.Body.ToString().Split('.', '+', '/').Last();
    MethodInfo.GetCurrentMethod().DeclaringType.GetProperty(name).SetValue(this, v, null);
    return name;
}
 
static void Main(string[] args)
{
    string name = StaticSet(() => StaticProp, 17);
 
    var obj = new Program();
    name = obj.Set(() => obj.Prop, 53);
 
    Console.WriteLine("{0} = {1}", name, StaticProp);
    Console.WriteLine("{0} = {1}", name, obj.Prop);
}
 
Output:
StaticProp = 17
Prop = 53
 
The trick here is to have a delgate of the property (that must have an accessible getter!) as means to transport the information of the property name in a kind of typesafe way to the Set...() method. The delecate is never executed, though. You still can abuse by providing any matching delegate, which screws up the thing.
 
Still: I think it's not worth the pain, never. See my comments as well as solution #1.
 
Cheers
 
Andi
  Permalink  
v3
Comments
Clifford Nelson at 10-Feb-12 15:07pm
   
Thanks for the input. Should have been more clear initially on the question. It would work except that the property is in a derived class, and the method is in the base class.
BillWoodruff at 10-Feb-12 18:55pm
   
+5 : I wish there were a special "bonus vote" I could add for your tenacity in helping this questioner both in comments, and code !
Andreas Gieriet at 10-Feb-12 19:51pm
   
Thanks again! Some topics just don't let me be... ;-)
Wonde Tadesse at 11-Feb-12 11:16am
   
5+
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

Hello Clifford,
 
maybe it helps if I first elaborate a bit on lambda expressions and then explain why it is not possible what you aim to do with properties.
 

Delegate: what they are for

 
A delegate is the means of C# to hold a handle to a method without executing the method. Once you have that handle, you can execue the method the handle points to at any time.
 
This is deferred execution. This is the primary purpose of delegates.
 

Ways to define delegates

 

The traditional way

 
The traditional way is to define a delegate type and use it wherever you need that deferred execution capability, e.g.
 
// define your own delegate type
public delegate void PrintStringDelegate(string arg);
 
// your print method
public static void ToConsole(string s)
{
    Console.WriteLine("{0}", s);
}
 
// define a variable that can hold a delegate
PrintStringDelegate print;
 
// "plain old" C# ...
print = new PrintStringDelegate(ToConsole);
 
// ...or more convenient abbreviation...
print = ToConsole;
 
// ... or anonymous function (a nameless method that takes a string argument)
print = delegate(string s) { Console.WriteLine("{0}", s); };
 
// ... and finally execute it where appropriate:
print("Hello deferred world!");
 

Become a bit fancy: Action, Action<...>, and Func<...>

 
Instead of defining your own delegate type, you may use the already predefined generic equivalents. In the above case we have an action that takes one string argument (a function would return a value, but the example above doesn't, so, the Func is not the right generic delegate).
 
E.g. the same as above, but with Action:
 
// no need for your own delegate type: take Action instead direclty for the variable:
Action<string> print;
 
// "plain old" C# ...
print = new Action<string>(ToConsole);
 
// ...or more convenient abbreviation...
print = ToConsole;
 
// ... or anonymous function (a nameless method that takes a string argument)
print = delegate(string s) { Console.WriteLine("{0}", s); };
 
// ... and finally execute it where appropriate:
print("Hello deferred world!");
 
BTW: there are further such generic delegates defined for convenience, e.g. Predicate<in T>, which is identical to Func<in T, bool>, and again identical to public delegate bool MyPredicateDelegate<in T>(T arg);.
 

Even more fancy: lambda expressions

 
As we've seen above, we can "simplify" my taking Action and Func in place of our own delegate type definition.
 
We can also define the method the delegate points inplace, i.e. at the point where we define the delegate variable. This was already possible with the anonymous methods, e.g.
 
// anonymous function (a nameless method that takes a string argument)
print = delegate(string s) { Console.WriteLine("{0}", s); };
 
Lambda expression allow to simplify that further, e.g.,
 
// lambda syntax to write an anonymous function
print = (s) => { Console.WriteLine("{0}", s); };
 
Lambda expressions are anonymous methods, identical in effect to the anonymous methods defined via the delegate keyword as shown above.
 
Even lambda expressions can be of any complexity, they are most handy for small inline expressions, therefore, there are some abbreviatons possible, e.g.
 
// one arg = no parenthesis needed
print = s => { Console.WriteLine("{0}", s); };
 
// single statement in the block = curly braces not needed
print = s => Console.WriteLine("{0}", s);
 
A nicety of lambda expresions is that you can use variables from its immediate environment (unlike methods), e.g.
 
string tag = "";
print = s => Console.WriteLine("{0}: {1}", tag, s);
 
tag= "Error";
print("some");
tag= "Warning";
print("more text");
 
The output is:
Error: some text
Warning: more text
 
Remember: what we have here are still delegates for deferred execution.
 

Delegates and Expression<...>

 
Expression<...> is not a class like any other class: it is a class that the compiler knows more about than on any common class. The Expression<...> class represents a lambda expression as the compiler sees it.
 
The aim of the Expression<...> class is to allow analyzing the lambda expression by C# code at runtime. This was needed to allow implementing any kind of data provider for Linq.
 
The C# language mandates that a variable of type Expression<...> can only hold a literal lambda expression. Not to be confused with assigning a delegate that might have been set to a lambda expression. The assignment is evaluated at compile time by the C# compiler (you remember: it is a class the compiler knows more about than of other common classes).
 
E.g. one can assign a lambda expression to a variable of type Expression<...>:
Expression<Action<string>> e = s => Console.WriteLine("{0}", s);
 
But one can not assign a delegate to that varialbe, e.g. this will not compile:
 
Action<string> print = s => Console.WriteLine("{0}", s);
Expression<Action<string>> e = print; // see error below...
 
The error is:
Cannot implicitly convert type 'System.Action<string>' to 'System.Linq.Expressions.Expression<System.Action<string>>'
 
You would have to pass a lambda expression again:
 
Action<string> print = s => Console.WriteLine("{0}", s);
Expression<Action<string>> e = s=>print(s);
 

Execution of delegate versus execution of Expression

 
A delegate is executed by "calling" it with the needed parameters, e.g.
 
print = s => { Console.WriteLine("{0}", s); };
print("Hello...");
 
An expression has to be compiled before executed (if that was needed, but usually this is not the primary purpose of the using the Expression<...> class):
 
Expression<Action<string>> e = s => Console.WriteLine("{0}", s);
Action<string> action = e.Compile();
action("Hello...");
 
BTW: If execution of the lambda expression is the main purpose then delegates will do it. If analyzing the structure of the lambda expression, the Expression<...> class is the "tool of choice".
 

Properties and lambda expressions

 
Properties have a dominant role in the .Net framework. They are preferrably used in serialization and in all the declarative interface descriptions (WCF, WPF, etc.).
 
So, one might be tempted to construct some "magic" wrapper functions to pass "a reference to a property" and do some assignment to it and trigger some events, etc.
 
Since a lambda expression's body is like a function body (maybe with some syntactic sugar to abbreviate the writing of them), a lambda expression of the following form is calling the getter of the property (This is not a reference to the property.
 
Func<int> func = ()=>obj.Prop;
 
There is no way in C# to pass a reference of a property anywhere.
 
Now, why not passing an Expression<...> instance to the "magic" method? E.g.
 
public static void MagicFunction(Expression<Func<int>> prop)
{
   // aim:
   // 1. get the name of the property for some magic action
   // 2. assign a value to the propery
}
 
MagicFunction(()=>obj.Prop);
 
 
Getting the name of the property is possible. It depends on the effort you put into making this robust (i.e. avoid abuse of the magic function with say MagicFunction(()=>12);).
 
Now, assigning to the property is also possible, but this is a semantic "non-sense": you pass a getter to set the property.
 
The way was to get the propery by name from the given type or instance and call SetValue(...) on that.
 
// static or instance properties
public static void Set<C, V>(C obj, Expression<Func<V>> p, V v)
{
    string name = p.Body.ToString().Split('.', '+', '/').Last(); // not robust...
    typeof(C).GetProperty(name).SetValue(obj, v, null);
}
// static properties
public static void Set<C, V>(Expression<Func<V>> p, V v)
{
    Set<C, V>(default(C), p, v);
}
 
Usage:
Set<program,>(()=>StaticProp, 123);
Program obj = new Program();
Set(obj, ()=>obj.Prop, 234); // note: the generic args are deduced
 

Summary

 
After my lengthly introduction and elaboration on delegates, lambda expressions and finally the Expression<...> class, the simple conclusion is that you can do some magic stuff (which is hopefully not so magic any more). But just since you could do it does not mean you should do it.
 
I consider abusing the Expression<...> and the getter of a property to do an assignment on the property is too much of a stretch for semantic integrity.
 
Now that you got the background you might agree Wink | ;-)
 
Cheers
 
Andi
 
PS: Now I ended up writing a solution almost in extent and form of an article... Wink | ;-) Have fun!
  Permalink  
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 295
1 Maciej Los 280
2 Afzaal Ahmad Zeeshan 224
3 BillWoodruff 205
4 Sergey Alexandrovich Kryukov 195
0 OriginalGriff 6,499
1 Sergey Alexandrovich Kryukov 6,048
2 DamithSL 5,193
3 Manas Bhardwaj 4,657
4 Maciej Los 4,120


Advertise | Privacy | Mobile
Web04 | 2.8.1411019.1 | Last Updated 11 Feb 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100