Expression.Bind() - what does it actually do? - c#

So I've been playing with dynamically building expression trees lately and came across this method, which seems kinda odd. At first I thought "oh cool this is exactly what I need" after constantly writing code along the lines of
var left = member is FieldInfo ? Expression.Field(instance, (FieldInfo)member) : Expression.Property(instance, (PropertyInfo)member);
var right = ...
var assign = Expression.Assign(left, right);
Yes, I know there is Expression.PropertyOrField() call, but it does roundtrip back to reflection to find member by name, where as I typically already have MemberInfo instance.
So anyway, I thought Expression.Bind() would be useful to me, but it does something I don't really understand. Given the following code:
void Main()
{
var m = typeof(Foo).GetField("Bar");
Expression.Bind(m, Expression.Constant("")).Dump();
}
public class Foo
{
public string Bar;
}
it produces MemberAssignment expression Bar = "". But there is no instance and no static reference. How would I ever apply this expression to and instance of Foo? I can't find any example of this method being used.

Object-Initializer expressions.
Let's say you had:
public class Foo
{
public int Property { get; set; }
}
Then you could do:
var parameter = Expression.Parameter(typeof(int), "i");
var newExpr = Expression.New(typeof(Foo));
var bindExprs = new[]
{
Expression.Bind(typeof(Foo).GetProperty("Property"), parameter)
// You can bind more properties here if you like.
};
var body = Expression.MemberInit(newExpr, bindExprs);
var lambda = Expression.Lambda<Func<int, Foo>>(body, parameter);
which is something like:
i => new Foo { Property = i }
Old:
I can't help you solve the "performance issue" you are determined to solve (will using Expression.PropertyOrField really introduce a bottleneck in your application? I'm somewhat skeptical. You should determine this before optimizing prematurely) (EDIT: Apologies for incorrectly assuming that this was a perf optimization, and as you've found out yourself, Expression.MakeMemberAccess is what you need), but I can tell you what Expression.Bind is useful for.

Related

Convert string to lambda expression that contains variables from other classes

What I've been trying to do is convert a string of the form:
"StudentDatabase.avgHeight > 1.7"
to a lambda expression that looks like this:
() => StudentDatabase.avgHeight > 1.7;
I tried something in the lines of this:
/* String splitting and parsing occurs here */
var comparison = Expression.GreaterThan(
Type.GetType("MyNamespace.StudentDatabase").GetField("avgHeight"),
Expression.Constant(1.7)
);
var lambda = Expression.Lambda<Func<bool>>(comparison).Compile();
Of course something like this wouldn't work since the GetField() method returns type FieldInfo and not Expression.
Here's a list about useful stuff you might want to know about my sample code:
The StudentDatabase class is a static class that contains a static field avgHeight.
I have already done the part of the code that parses the string so there's no need to include it in any provided solutions.
This is just an example so you can change the string and variable/class names if you wish so.
This is not an assignment so feel free to post source code. In fact, that would be greately appreciated.
TL;DR; What I'm trying to do is use LINQ Expressions to access variables from other places of the code.
I disagree with the following comments, Linq expressions is a viable way to do this sort of thing. The below code accomplishes it. However, please consider the following code:
namespace MyNamespace
{
class Program
{
static void Main(string[] args)
{
/* String splitting and parsing occurs here */
var comparison = Expression.GreaterThan(
Expression.Field(null, Type.GetType("MyNamespace.StudentDatabase").GetField("avgHeight")),
Expression.Constant(1.7)
);
var lambda = Expression.Lambda<Func<bool>>(comparison).Compile();
StudentDatabase.avgHeight = 1.3;
var result1 = lambda(); //is true
StudentDatabase.avgHeight = 2.0;
var result2 = lambda(); //is false
}
}
class StudentDatabase
{
public static double avgHeight = 1.3;
}
}
Should result2 be true or false? If you want it to be true, then you have more work to do.
I've created this as a sort of framework you can work off of. It does not use LINQ but will output the value specified by the string.
var type = Type.GetType("MyNamespace.StudentDatabase");
if (type != null)
{
var field = type.GetField("avgHeight");
if (field != null)
{
Func<bool> lambda = () => (double)field.GetValue(type) > 1.7;
}
}
There is some error checking you could add/remove. The other areas such as the > and 1.7 can be parsed elsewhere and inserted but this is how you could get a value from the strings.

Explicit Boxing between does not work properly with Expression.Convert?

Recently, I came across some troubles about boxing using Expression Trees when I was developing my homemade SQLite ORM. I am still coding again C# 3.5.
To make a long story short, I'm gonna use this simple class definition:
[Table]
public class Michelle
{
[Column(true), PrimaryKey]
public UInt32 A { get; set; }
[Column]
public String B { get; set; }
}
So this from that POCO class definition I instantiated a new object and my ORM engine converted that object into a record and it's properly inserted. Now the trick is that when I get back the value from SQLite I got an Int64.
I thought that my delegate setter was OK because it's an Action<Object, Object> but I still got that InvalidCastException. Seems that the Object (parameter, an Int64) is attempted to be cast into a UInt32. Unfortunately it does not work. I tried to add some Expression.Constant and Expression.TypeAs (that one does not really help for value typed objects).
So I am wondering what sort of things are wrong in my setter generation.
Here below is my setter generation method:
public static Action<Object, Object> GenerateSetter(PropertyInfo propertyInfo)
{
if (!FactoryFastProperties.CacheSetters.ContainsKey(propertyInfo))
{
MethodInfo methodInfoSetter = propertyInfo.GetSetMethod();
ParameterExpression parameterExpressionInstance = Expression.Parameter(FactoryFastProperties.TypeObject, "Instance");
ParameterExpression parameterExpressionValue = Expression.Parameter(FactoryFastProperties.TypeObject, "Value");
UnaryExpression unaryExpressionInstance = Expression.Convert(parameterExpressionInstance, propertyInfo.DeclaringType);
UnaryExpression unaryExpressionValue = Expression.Convert(parameterExpressionValue, propertyInfo.PropertyType);
MethodCallExpression methodCallExpression = Expression.Call(unaryExpressionInstance, methodInfoSetter, unaryExpressionValue);
Expression<Action<Object, Object>> expressionActionObjectObject = Expression.Lambda<Action<Object, Object>>(methodCallExpression, new ParameterExpression[] { parameterExpressionInstance, parameterExpressionValue });
FactoryFastProperties.CacheSetters.Add(propertyInfo, expressionActionObjectObject.Compile());
}
return FactoryFastProperties.CacheSetters[propertyInfo];
}
So basically:
// Considering setter as something returned by the generator described above
// So:
// That one works!
setter(instance, 32u);
// This one... hm not really =/
setter(instance, 64);
I should probably add another Expression.Convert but I do not really know how it would help to make it work. Since there is already one supposed to (attempt to) convert from any Object to the property type (here in my example the UInt32 type).
Any idea to fix it up?
For this answer, assume the following is defined:
object myColValueFromTheDatabase = (object)64L;
Expression.Convert determines statically how the conversion is to be performed. Just like C# does. If you write (uint)myColValueFromTheDatabase this will not succeed at runtime because unboxing just does not work that way. Expression.Convert does a simple unboxing attempt as well. That's why it fails.
You would need to do either of the following:
(uint)(long)myColValueFromTheDatabase
Convert.ToUInt32(myColValueFromTheDatabase)
In case (1) you need to unbox to the exact-match type first, then change the bits. Case (2) resolves this using some helper methods. Case (1) is faster.
To do this with the expression API, insert another Expression.Convert.
This should get you started:
public static T LogValue<T>(T val)
{
Console.WriteLine(val.GetType().Name + ": " + val);
return val;
}
static void Main(string[] args)
{
Expression myColValueFromTheDatabase = Expression.Convert(Expression.Constant(1234L), typeof(object));
myColValueFromTheDatabase = Expression.Call(typeof(Program), "LogValue", new[] { myColValueFromTheDatabase.Type }, myColValueFromTheDatabase); //log
Expression unboxed = Expression.Convert(myColValueFromTheDatabase, typeof(long));
Expression converted = Expression.Convert(unboxed, typeof(uint));
var result = Expression.Lambda<Func<uint>>(converted).Compile()();
Console.WriteLine(result);
}

Reading a property value with a lambda expression

I'm writing a file generic block for my application and started with using Lambda expressions for managing my rule sets for block generation to avoid the pitfalls of magic strings, configuration hell etc.
Inside my mapping class I have lines similar to:
Map(x => x.Name).Length(20).PadLeft(true).PaddingChar("#");
This works fine and isn't where my question dwells, where I setup saving my information about the expression is in the Map method:
public override IPropertyMap Map(Expression<Func<T, object>> expression)
{
var propertyMap = new FixedLengthPropertyMap
{
//Length = 20,
//PaddingCharacter = " ",
PadLeft = false,
PropertyInfo = ReflectionHelper.GetProperty(expression)
};
_properties.Add(propertyMap);
return propertyMap;
}
_properties is just a List<IPropertyMap> that stores my info where my question from what is the best way to have a real object's data be read from the properties currently I came up with something similar to this:
var map = new AgentMap();
var agent = new Agent {Name = "Bob"};
string output = map.Write(agent);
public override string Write<T>(T agent)
{
var initial = _properties[0];
return initial.PropertyInfo.GetValue(agent, null) as string;
}
Is there a better way than using the GetValue method since earlier on I'm using an expression tree?
I don't see why you really need to use expression trees at all. Just make the Map method take a Func<T, object> and store that:
public override IPropertyMap Map(Func<T, string> fetcher)
{
var propertyMap = new FixedLengthPropertyMap
{
//Length = 20,
//PaddingCharacter = " ",
PadLeft = false,
Delegate = fetcher // Delegate is of type Delegate
};
_properties.Add(propertyMap);
return propertyMap;
}
Then:
public override string Write<T>(T agent)
{
var initial = _properties[0];
Func<T, string> fetcher = (Func<T, string>) initial.Delegate;
return fetcher(agent);
}
Is there any reason you particularly wanted to know the property and use an expression tree?
In part, it depends on what your scenario is. The "simple" answer is to just compile the expression and invoke it, but that has a potential performance impact if you are doing it in a tight loop (passing a delegate would be a lot quicker).
I'm not sure whether if would apply in this particular case (because of the agent), but to avoid doing too much expression compilation, you can look for simple scenarios and read the value directly from the expression tree; a little bit of PropertyInfo/FieldInfo is going to be quicker than compiling it...
For more, look at TryEvaluate here, and how it is used with Compile as a backup strategy (although you have the advantage of a known delegate type).

What's the best way to define & access selected properties in C#?

From my recent question, I try to centralize the domain model by including some silly logic in domain interface. However, I found some problem that need to include or exclude some properties from validating.
Basically, I can use expression tree like the following code. Nevertheless, I do not like it because I need to define local variable ("u") each time when I create lambda expression. Do you have any source code that is shorter than me? Moreover, I need some method to quickly access selected properties.
public void IncludeProperties<T>(params Expression<Func<IUser,object>>[] selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>
(
u => u.ID,
u => u.LogOnName,
u => u.HashedPassword
);
Thanks,
Lambdas are great for many scenarios - but if you don't want them, perhaps simply don't use them? I hate to say it, but simple strings are tried and tested, especially for scenarios like data binding. If you want fast access, you could look at HyperDescriptor, or there are ways of compiling a delegate to the property accessors, or you can build an Expression from the string and compile it (including a cast to object if you want a known signature, rather than calling the (much slower) DynamicInvoke).
Of course, in most cases even crude reflection is fast enough, and isn't the bottleneck.
I suggest starting with the simplest code, and check it is actually too slow before worrying about it being fast. If it isn't too slow, don't change it. Any of the above options would work otherwise.
Another thought; if you are using Expression, you could do something like:
public void IncludeProperties<T>(
Expression<Func<T,object>> selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>( u => new { u.ID, u.LogOnName, u.HashedPassword });
and then take the expression apart? A bit tidier, at least... here's some sample code showing the deconstruction:
public static void IncludeProperties<T>(
Expression<Func<T, object>> selectedProperties)
{
NewExpression ne = selectedProperties.Body as NewExpression;
if (ne == null) throw new InvalidOperationException(
"Object constructor expected");
foreach (Expression arg in ne.Arguments)
{
MemberExpression me = arg as MemberExpression;
if (me == null || me.Expression != selectedProperties.Parameters[0])
throw new InvalidOperationException(
"Object constructor argument should be a direct member");
Console.WriteLine("Accessing: " + me.Member.Name);
}
}
static void Main()
{
IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword });
}
Once you know the MemberInfos (me.Member in the above), building your own lambdas for individual access should be trivial. For example (including a cast to object to get a single signature):
var param = Expression.Parameter(typeof(T), "x");
var memberAccess = Expression.MakeMemberAccess(param, me.Member);
var body = Expression.Convert(memberAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, param);
var func = lambda.Compile();
Here's the shortest expression I can come up with:
public static void IncludeProperties(Expression<Action<IUser>> selectedProperties)
{
// some logic to store parameter
}
public static void S(params object[] props)
{
// dummy method to get to the params syntax
}
[Test]
public void ParamsTest()
{
IncludeProperties(u => S(
u.Id,
u.Name
));
}

Retrieving an Expression from a property and adding it to an expression tree

I've tried to simplify this example, as the actual code I'm playing with is more complex. So while this example may seem silly, bear with me. Let's say I'm working with the AdventureWorks database and I decide I want to add a property called Blarg to the Product table that returns an expression that contains code I would like to use in several places:
public partial class Product
{
public Expression<Func<Product, string>> Blarg
{
get { return product => product.ProductModelID.HasValue ? "Blarg?" : "Blarg!"; }
}
}
What I want to do is create an expression expression tree, have it get the Expression from Product.Blarg, and group by the result. Something like this:
var productParameter = Expression.Parameter(typeof(Product), "product");
// The Problem
var groupExpression = Expression.Lambda<Func<Product, string>>(
Expression.Invoke(
Expression.Property(productParameter, "Blarg"),
productParameter),
productParameter);
using (AdventureWorksDataContext db = new AdventureWorksDataContext())
{
var result = db.Products.GroupBy(groupExpression).ToList();
// Throws ArgumentException: "The argument 'value' was the wrong type.
// Expected 'System.Delegate'.
// Actual 'System.Linq.Expressions.Expression`1[System.Func`2[LINQ_Test.Product,System.String]]'."
}
Obviously groupExpression is incorrect (see the code comment for the exception), but I'm not sure how I should be doing it. What I thought I was saying is "get the Expression from the product.Blarg, execute it, and return the string result." I guess that's not what I'm actually saying there, though. I'm still trying to figure out expression trees. Any idea how I could pull this off?
When you call Expression.Invoke, the first argument must be an existing LambdaExpression - it can't be an Expression to a LambdaExpression. Or in other words: it isn't going to evaluate Product.Blarg per row and use a different sub-expression each time.
Instead, you would retrieve this lambda first, perhaps making it static and accessing it via reflection if you only know it by name:
var lambda = (LambdaExpression) typeof(Product)
.GetProperty("Blarg").GetValue(null,null);
And pass lambda in as the argument to Expression.Invoke; here's a fully working LINQ-to-Objects example showing this (via AsQueryable()):
using System;
using System.Linq;
using System.Linq.Expressions;
public partial class Product
{
public static Expression<Func<Product, string>> Blarg
{
get { return product => product.ProductModelID.HasValue ? "Blarg?" : "Blarg!"; }
}
public int? ProductModelID { get; set; }
static void Main()
{
var lambda = (LambdaExpression)typeof(Product)
.GetProperty("Blarg").GetValue(null, null);
var productParameter = Expression.Parameter(typeof(Product), "product");
// The Problem
var groupExpression = Expression.Lambda<Func<Product, string>>(
Expression.Invoke(
lambda,
productParameter),
productParameter);
var data = new[] {
new Product { ProductModelID = 123},
new Product { ProductModelID = null},
new Product { ProductModelID = 456},
};
var qry = data.AsQueryable().GroupBy(groupExpression).ToList();
}
}
var qry = data.AsQueryable().GroupBy(Blarg).ToList();
That works, same as Marc's code.
Note: Blarg is already correct, there is no reason to 're-invoke' it.

Categories