Expression<Func<T>> - Get Property's calling object instance without Compile() - c#

EDIT: Updated example to what I'm actually doing.
EDIT 2: The why:
My class "takes hold" of a property setter (or method, anonymous or not) and "controls" it for a period of time. The user could try and attach another instance of my class and attach that to a property that is already "controlled." I need a way to detect these conflicts reliably. I could forego the () => { property } method but that requires the user to wrap the target property in a method and, if he/she wants conflict detection, to pass in the object containing the property. Doing it that way introduces higher risk of bugs as they may type in the wrong object and the class wouldn't have any means to check for them.
I am unable to utilize the Lambda Compile() because I am targeting AOT in addition to JIT.
I have a method that takes an
Expression<Func<T>>
as an argument. The Expression always evaluates to a property with a setter of Type T.
private static TargetInfo GetTargetInfo<T>(Expression<Func<T>> _propertyExpression, out Action<T> _setter)
{
//Get Property info
var propInfo = ((MemberExpression)_propertyExpression.Body).Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException("_propertyExpression must be a property.");
var declType = propInfo.DeclaringType;
var methodInfo = propInfo.GetSetMethod(true) ?? declType.GetProperty(propInfo.Name).GetSetMethod(true);
if (methodInfo == null)
throw new Exception("Could not create setter from property '" + _propertyExpression + "'");
var isStaticProp = methodInfo.IsStatic;
//Get Target Object
object targetObject = null;
var memberExp = _propertyExpression.Body as MemberExpression;
var bodyExp = memberExp.Expression;
if (bodyExp != null)
// PROBLEM LINE BELOW - Can't use Compile() *********************************
targetObject = Expression.Lambda<Func<object>>(bodyExp).Compile()();
// PROBLEM LINE ABOVE *******************************************************
else if (isStaticProp)
targetObject = memberExp.Member.DeclaringType;
else
throw new Exception("Could not determine target object. Use Action<T> overload. (no conflict detection)");
//Cache setter of property
if (isStaticProp)
_setter = (Action<T>) Delegate.CreateDelegate(typeof (Action<T>), methodInfo);
else
_setter = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), targetObject, methodInfo);
return new TargetInfo(methodInfo, targetObject);
}
The expression (_propertyExpression) is always of a property. And the property always has a setter.
I need to extract the property's setter as Action (which I can do
no problem)
I also need the instance of the object containing this
property without using Compile() as it is not available on some of
the target platforms I am targeting.
The reason I need the instance is to determine whether or not another object instance of my class is currently utilizing that property SETTER on THAT object. (No Threading, just usage over a span of time) I store the object Instance and property setter info together as a key, if two keys that are equal that exist then there is a conflict and it is handled based on the user's configuration settings of my class.
I am able to get the object instance for simple expressions like:
() => MyProperty
or
() => MyObjectInst.PropertyFoo
or
() => MyStaticClass.PropertyFooBar
No Sweat!
But what if the user does this:
//Need instance of 'someObject' here.
() => SomeArray[idx].someObject.propertyA
or blow my top:
//Need instance of 'someField[4]' here
() => SomeStaticClass.somePropertyList[5].SomeDictionary[objKey].SomeProperty.someFieldArray[4].propertyB
AAAK!
I've been looking at this for a while and I BELIEVE that I need to traverse the tree BACK to the base object (ConstantExpression) then start evaluating back UP the tree using the info collected walking to the front. Given the examples above I decided that I need "bigger guns".
Is there an easier way to get the property's caller's instance other than completely walking the tree WITHOUT using Compile()? Please explain if so!
If not 1. If anyone could point me in the right direction on how to traverse the tree and handle stuff like the above. That would be great. I'm not finding a whole lot of info on traversing Expression Trees, expression types, etc. Even a reference to a recommended book specific to the subject would be helpful.
sigh Should I just give up and force the user to use simple expressions.
ie. Do not allow the user to type in lengthy property access lines.
Clarification:
The setter is being cached for use by a mechanism class "FOO" that will be setting this value an UNKNOWN range of values of type T over some defined period of time. The object instance is cached and used as a key to detect the case that another instance of FOO tries to attach and set values to the same property on that same object. The object instance is used to detect these conflicts and also to keep track of all of the "FOO"s attached to any particular object. The user can attach multiple "FOO"s to the same object, to different properties. In the case that the user attaches an instance of FOO to a property on an object that already has a FOO attached for that property, a conflict event occurs. FOO can be configured on how to handle when that happens.

Here's the problems with your suggested approaches:
Is there an easier way to get the property's caller's instance other
than completely walking the tree WITHOUT using Compile()? Please
explain if so!
Short answer, no. Expressions are meant to be compiled. Either into .NET Funcs/Actions or some other platform (LINQ-to-Entities essentially compiles them into SQL). If you don't want to compile it, you're probably using the wrong tool.
If not 1. If anyone could point me in the right direction on how to
traverse the tree and handle stuff like the above. That would be
great. I'm not finding a whole lot of info on traversing Expression
Trees, expression types, etc. Even a reference to a recommended book
specific to the subject would be helpful.
The best way to traverse an Expression tree is by inheriting from ExpressionVisitor. A good blog to start with would be Matt Warren's blog http://blogs.msdn.com/b/mattwar/, read the series on implementing IQueryable. But no, it's not easy.
One could (theoretically) inherit from ExpressionVisitor to walk down/up the chain to the original instance. But you would then have to walk back up/down the chain somehow, and the easiest way to do that would be by compiling the child Expressions. You could, theoretically, use Reflection to walk back, as your answer tries, but I hope you're distinctly getting the impression you have chosen the wrong tool if your No-Compiling stance is iron-clad.
sigh Should I just give up and force the user to use simple expressions.
You haven't outlined the benefits/drawbacks of this.

I have confirmed that the below works on for MONO -> iOS... At least with the basics and arrays. Haven't been able to get the Dictionary/List rolling. It seems AOT doesn't like MethodInfo.Invoke.
EDIT:
I found this answer on MSDN:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/af305a45-36e4-4607-9190-f1b33a0bea57/get-class-instance-from-lambda-expression
It traverses the Expression tree, evaluating each part of the tree as necessary and finally returns the containing object of the property specified.
Put in this (along with adding the method code below in):
targetObject = GetContainer(_propertyExpression);
instead of this:
targetObject = Expression.Lambda<Func<object>>(bodyExp).Compile()();
in the code above.
I have yet to do full testing on it on other platforms and I'm sure I'll run into other cases where I need to add more cases but this might be enough to help someone else and enough to keep me going and I'll try and keep this updated as I run into more:
public static object GetContainer<T>(Expression<Func<T>> propertyLambdaExpression)
{
return Evaluate((propertyLambdaExpression.Body as MemberExpression).Expression);
}
public static object Evaluate(Expression e)
{
switch (e.NodeType)
{
case ExpressionType.Constant:
return (e as ConstantExpression).Value;
case ExpressionType.MemberAccess:
{
var propertyExpression = e as MemberExpression;
var field = propertyExpression.Member as FieldInfo;
var property = propertyExpression.Member as PropertyInfo;
var container = propertyExpression.Expression == null ? null : Evaluate(propertyExpression.Expression);
if (field != null)
return field.GetValue(container);
else if (property != null)
return property.GetValue(container, null);
else
return null;
}
case ExpressionType.ArrayIndex: //Arrays
{
var arrayIndex = e as BinaryExpression;
var idx = (int)Evaluate(arrayIndex.Right);
var array = (object[])Evaluate(arrayIndex.Left);
return array[idx];
}
case ExpressionType.Call: //Generic Lists and Dictionaries
{
var call = e as MethodCallExpression;
var callingObj = Evaluate(call.Object);
object[] args = new object[call.Arguments.Count];
for (var idx = 0; idx < call.Arguments.Count; ++idx)
args[idx] = Evaluate(call.Arguments[idx]);
return call.Method.Invoke(callingObj, args);
}
default:
return null;
}
}

Related

Access parameter/variable passed to Invoke-call

I'm trying to build some dynamic queries for my underlying database using LinqKit and the expandable-extensions.
In my code I have a property which looks like
private Expression<Func<MyModel, MyConfig, MyResult>> Parent
{
get
{
var modelParam = Expression.Parameter(typeof(MyModel), "myModel");
var configParam = Expression.Parameter(typeof(MyConfig), "config");
var conditionalExpression = Expression.Call(configParam, typeof(MyConfig).GetMethod("ShowParent"), Expression.Constant("SomeName"));
// how to decide whether to return an expression or null?
// build expression or return constant null-expression
}
}
which I call Parent.Invoke(myModel, config).
Is there any chance to gain access to the config-param which is passed to the Invoke-call to determine inside the getter whether to return a real Expression or just null?
The MyConfig class has a method bool ShowParent(string parentName) which I would like to call inside the getter to determine what to do?
Is this possible that way? If not, are there any good points where to start with?

CodeType get generic parameters

We're using the Visual Studio CodeModel and have some problems to get the generic parameters of a CodeType. How to obtain them without parsing the FullName ourselves?
It is hinted (although not marked an answer) in How can I get the generic constraints from CodeInterface as a CodeType object? that there is no other way, however, this is not really believable as:
System.Func<Outer.Inner>
would not be defined: You cannot know if the generic parameter you've parsed (Outer.Inner) is referring to the namespace Outer containing a class Inner or if it is referring to the class Outer having an inner class Inner (and yes, it is not Outer+Inner in such cases).
If somebody at least knows how to tell the FullName property to show nested classes with a + sign this would be great too.
I think the answer here is pretty definitive. This isn't supported by DTE or DTE2 and is unlikely to be supported in the future.
The only way currently is to use Roslyn, which is not acceptable for those of us that don't want to use pre-release software. I also haven't looked into what kinds of dependencies that will entail (do users of my component need to install Roslyn?).
You could use a regular expression to get the types from the FullName string. But, for those of us in the real world who need the token (T) to concrete type (System.String) mapping, this is not an option.
I can't find a way to do it for any generic type, but if you need to do it for a specific type, it is possible in some cases.
For instance, I have the following code to check if a type is a collection, and if it is, get the element type:
private static bool IsCollectionType(CodeType type, out CodeType elementType)
{
// string implements IEnumerable<char>, but we don't want to treat it as a collection
if (type.FullName == "System.String")
{
elementType = null;
return false;
}
var enumerable = type.Bases.OfType<CodeInterface>().FirstOrDefault(i => i.FullName.StartsWith("System.Collections.Generic.IEnumerable<"));
var method = enumerable?.Members.OfType<CodeFunction>().FirstOrDefault(m => m.Name == "GetEnumerator");
var enumerator = method?.Type.CodeType;
var current = enumerator?.Members.OfType<CodeProperty>().FirstOrDefault(m => m.Name == "Current");
if (current != null)
{
elementType = current.Type.CodeType;
return true;
}
elementType = null;
return false;
}
As you can see, I'm not directly looking at the generic type argument, but instead I look at the type of IEnumerable<T>.GetEnumerator().Current. Of course, this requires specific knowledge about the type you're working with.

How can I access the value of the target of a Func<Client, bool>?

I have C# a method that is declared as the following:
public IEnumerable<ClientEntity> Search(Func<Client, bool> searchPredicate)
{
// Uses the search searchPredicate to perform a search.
}
This method gets called with something like:
string searchCriteria = "My Search Criteria";
bool searchOnlyActive = false;
myClientService.Search(c => c.Name.Contains(searchCriteria) && (c.Active || !searchOnlyActive));
Now, if I throw a breakpoint at the beginning of that method and I look at the searchPredicate properties in the Immediate Window, when I type searchPredicate.Target, I get something like this:
{MyNamespace.ClientsService.}
searchCriteria: "My Search Criteria"
searchOnlyActive: false
What I would like is to actually get the "My Search Criteria" value and the false value displayed there, like the debugger does, but I didn't manage to as the type of the Target property is something like "<>c__DisplayClass2" which I have no idea where that came from. I know it can be done because the debugger does it, I just don't know how.
Any ideas? Thanks!
<>c__DisplayClass2 is the class that the compiler invented to get the capture context. You can just use reflection:
object target = searchPredicate.Target;
if(target != null) {
foreach(var field in target.GetType().GetFields()) {
Console.WriteLine("{0}={1}", field.Name, field.GetValue(target));
}
}
which outputs:
searchCriteria=My Search Criteria
searchOnlyActive=False
However! Unless you understand anonymous methods and captured variables (and how that is implemented in terms of compiler-generated context classes), I don't think this will do what you want it to; for example, there could be no context (a Target that is null), or multiple nested contexts...
Also: expression trees via Expression<Func<Client,bool>> are far more inspectable, if that is your intent.

Writing a certain generic method

I have a series of methods to write, but I think there is some commonality (well, I know there is). The method I'd like to see will take two things, an object and... well, I'm not so sure about the second one, but probably a string.
The object should be generic, although it can only be from a set list (in this case, that commonality seems to be that they inherit from both INotifyPropertyChanging and INotifyPropertyChanged interfaces).
The string should be the name of a property within the generic object. It should be checked to see if that property exists within that object before being put into use (it would be used as a way to compare the objects by that given property).
So I guess the process would be... generic object gets passed into method (along with property name string). A check to see if the object contains the property. If it does, continue and somehow have access to 'object.PropertyName' where 'PropertyName' was the supplied string.
I don't know if it's easy or possible or even wise, but I know that it would save me some time.
Thanks in advance for any advice you might be able to offer with this.
Edit: Thanks for the all the replies so far guys. Let me clarify some things:
Clarification of 'access'
When I said, "... and somehow have access to 'object.PropertyName'", what I meant was that the method should be able to use that property name as if it were just a property of that object. So, let's say the string passed in was "ClientName", there would be the ability to read (possibly write, although at the moment I don't think so as it's just a check) object.ClientName, if it was determined that existed.
What I'm trying to do
I have a WCF service which accesses an SQL database using Linq. The objects I spoke of are entities, generated from the program SQLMetal.exe, so my objects are things like 'Client', 'User' and this sort of thing. I wrote a method which took a List of entities. This method added only those entities which did not exist within the collection (some could have been duplicates). It figured out which ones were duplicates by checking a property within the entity (which corresponds to data in a column of the database). It's that property which I figured might be variable.
It sounds like you don't really want to check if it's a certain type, and if that is so then you don't have to and its actually easier not to check the type. This shows how to check if the property exists and if it is readable and writeable and shows how to use it after it's found:
private void Form1_Load(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
PropertyInfo info = GetProperty(sb, "Capacity");
//To get the value of the property, call GetValue on the PropertyInfo with the object and null parameters:
info.GetValue(sb, null);
//To set the value of the property, call SetValue on the PropertyInfo with the object, value, and null parameters:
info.SetValue(sb, 20, null);
}
private PropertyInfo GetProperty(object obj, string property)
{
PropertyInfo info = obj.GetType().GetProperty(property);
if (info != null && info.CanRead && info.CanWrite)
return info;
return null;
}
I think only indexer properties can take parameters in C#. And I believe if you wrote properties in VB that take parameters and tried to reference that assembly in C# they would show up as methods instead of properties.
You could also write a function like this that would take 2 objects and a string for a property name and return the result of those properties matching:
private bool DoObjectsMatch(object obj1, object obj2, string propetyName)
{
PropertyInfo info1 = obj1.GetType().GetProperty(propertyName);
PropertyInfo info2 = obj2.GetType().GetProperty(propertyName);
if (info1 != null && info1.CanRead && info2 != null && info2.CanRead)
return info1.GetValue(obj1, null).ToString() == info2.GetValue(obj2, null).ToString();
return false;
}
Comparing the values of the properties might be tricky because it would compare them as objects and who knows how equality will be handled for them. But converting the values to strings should work for you in this case.
If you know the 2 objects are the same type then you can simplify it:
private bool DoObjectsMatch(object obj1, object obj2, string propetyName)
{
PropertyInfo info = obj1.GetType().GetProperty(propertyName);
if (info != null && info.CanRead)
return info.GetValue(obj1, null).ToString() == info.GetValue(obj2, null).ToString();
return false;
}
I think you're looking for something like:
public void SomeMethod<T>(T object, string propName)
where T : INotifyPropertyChanging, INotifyPropertyChanged
(
var type = typeof(T);
var property = type.GetProperty(propName);
if(property == null)
throw new ArgumentException("Property doesn't exist", "propName");
var value = property.GetValue(object, null);
)

Build an object from another object in C# using generic code

Let's say I have an object of Type User that looks like this:
User {
Name = "Bob",
Email = "Bob#gmail.com",
Class = NULL
}
Can anyone think of a way to take that object and create an object like this:
User {
Name = "Bob",
Email = "Bob#gmail.com"
}
Using entirely generic code? Meaning, I don't want to hard code anything to do with the Type, or the Properties because this code would need to be applied to every Entity on my site. (the "User" type is an Entity by the way, so use that if it helps you code this better).
I'm just trying to come up with a solution to a problem I have and I BELIEVE that Stub Entities may fix the problem, but I need to do it without hard coding any Types or Properties.
Use reflection to achieve this:
public void CopyValues<TSource, TTarget>(TSource source, TTarget target)
{
var sourceProperties = typeof(TSource).GetProperties().Where(p => p.CanRead);
foreach (var property in sourceProperties)
{
var targetProperty = typeof(TTarget).GetProperty(property.Name);
if (targetProperty != null && targetProperty.CanWrite && targetProperty.PropertyType.IsAssignableFrom(property.PropertyType))
{
var value = property.GetValue(source, null);
targetProperty.SetValue(target, value, null);
}
}
}
Generics are not gonna help you for this case. There might be some option in the Entity Framework but i am not really known with that.
It would however be possible using Reflection. You could try something like this:
public static void CopyProperties(object a, object b)
{
if (a.GetType() != b.GetType())
throw new ArgumentException("Types of object a and b should be the same", "b")
foreach (PropertyInfo property in a.GetType().GetProperties())
{
if (!property.CanRead || !property.CanWrite || (property.GetIndexParameters().Length > 0))
continue;
property.SetValue(b, property.GetValue(a, null), null);
}
}
Keep in mind tough that this requires all the properties you want to copy to have both a public setter and getter. Also there is the difference between "deep copy" vs "shallow copy" wich means if sub-objects are also copied or only referenced. This example will only reference them so it would be a "shallow copy"
This looks like a problem for reflection rather than generics (although generics can be used as a sneaky way of caching the strategy for reflection). Unless I misread it, you want to create a new instance and copy most of the members... Which reflection is good at, albeit relatively slow. You can improve the speed by using meta-programming; on the first run (per-type) generate an optimised version, perhaps using DynamicMethod or Expression, and store a typed delegate from that. Then just use the delegate.

Categories