Defining a method parameter context

It's complicated here. Is it possible, using any method, to implicitly determine the name of the property that is passed as a parameter to the method?

(This may seem like a duplicate of another question at first glance, but there are subtle but important differences, since we always work with properties that are key).

Here is an example script:

public class Foo { public string Bar { get; set; } } public void SomeStrangeMethod() { Foo foo = new Foo() { Bar = "Hello" }; string result = FindContext(foo.Bar); // should return "Bar" } public string FindContext(object obj) { // TODO? - figure out the property name corresponding to the passed parameter. // In this example, we need to somehow figure out that the value of "obj" // is the value of the property foo.Bar, and return "Bar" } 

Assume that inside the FindContext the passed parameter will always be a property of the object. Catch, we do not know which object.

Obviously, the problem can be easily solved by passing a second parameter that provides the missing context, i.e. ...

 FindContext(foo, foo.Bar); FindContext("Bar", foo.Bar); 

.... but this is not what I want. I want to be able to pass one parameter and determine the property name represented by the value.

I understand that when passing a parameter, the method context for FindContext does not contain enough information to determine this. However, using some sleight of hand around the stack and IL traces, perhaps we can still do this. The reason I think this should be possible:

  • The requirement is that the parameter passed to FindContext must always be a property of another object, and we know that using reflection we can get the specified property names.

  • Using StackTrace, we can get the call context.

  • From the context of the call, we must somehow find the character used.

  • From this symbol, we must either get the name of the property or the type of the caller, which through (1) should be able to convert to the property of the caller.

Does anyone know how to do this? Note. This question is complex, but I do not think this is impossible. I will not accept any "impossible" answers if someone cannot demonstrate why this is not possible.

+4
source share
4 answers

If you pass the lambda expression you can

 public class Foo { public string Bar { get; set; } } public void SomeStrangeMethod() { Foo foo = new Foo() { Bar = "Hello" }; string result = GetName(()=>foo.Bar); // should return "Bar" Debug.WriteLine(result); // "Bar" } public static string GetName<T>(Expression<Func<T>> expression) { return ExtractPropertyName(expression); } /// <summary> /// Extracts the name of a property from a suitable LambdaExpression. /// </summary> /// <param name="propertyExpression">The property expression.</param> /// <returns></returns> public static string ExtractPropertyName(LambdaExpression propertyExpression) { if (propertyExpression == null) { throw new ArgumentNullException("propertyExpression"); } var memberExpression = propertyExpression.Body as MemberExpression; if (memberExpression == null) { throw new ArgumentException(@"Not a member expression", "propertyExpression"); } var property = memberExpression.Member as PropertyInfo; if (property == null) { throw new ArgumentException(@"Not a property", "propertyExpression"); } var getMethod = property.GetGetMethod(true); if (getMethod.IsStatic) { throw new ArgumentException(@"Can't be static", "propertyExpression"); } return memberExpression.Member.Name; } 
+2
source

The MVVM Light Toolkit uses sugar expression trees in C #, passing "properties" to implement INotifyPropertyChanging and INotifyPropertyChanged . See ObservableObject.cs for more details.

 void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression) { var handler = PropertyChanged; if (handler != null) { var propertyName = GetPropertyName(propertyExpression); handler(this, new PropertyChangedEventArgs(propertyName)); } } 

Then the calling code can use this:

 RaisePropertyChanged(() => this.Property); 

Instead of relying on hard-coded strings as follows:

 RaisePropertyChanged("Property"); 
+3
source

No - this is not always possible.

 3. Out of the calling context, we should be able to somehow locate the symbol being used. 

This is the part that fails. You cannot get at run time the character used for the method parameter (at least not directly). There are no tools in the Reflection library that provide this type of analysis or metadata.

Thus, this may be potentially possible with a large IL analysis. If you used a tool such as Mono.Cecil to decompile the assembly, find the "call context" and then examine IL to call the method in question.

+1
source

To find out the name of a property from Expression without explicitly specifying the type of the object in Expression , you need an extension method:

 public static class ObjectExt { public static string FindContext<T,TProp>(this T obj, Expression<Func<T,TProp>> expression) { return ( expression.Body as MemberExpression ).Member.Name; } } 

Then, if we put it in a code sample

 public class Foo { public string Bar { get; set; } } public void SomeStrangeMethod() { Foo foo = new Foo() { Bar = "Hello" }; string result = foo.FindContext(s => s.Bar); // should return "Bar" } 
+1
source

All Articles