I have an expression tree function from a previous SO question. It basically allows the conversion of a data row into a specific class.
This code works fine, unless you're dealing with data types that can be bigger or smaller (eg. Int32/Int64).
The code throws an invalid cast exception when going from an Int64 to an Int32 when the value would fit in an Int32 (eg. numbers in the 3000).
Should I?
Attempt to fix this in the code? (If so, any pointers?)
Leave the code as it is.
private Func<SqlDataReader, T> getExpressionDelegate<T>()
{
// hang on to row[string] property
var indexerProperty = typeof(SqlDataReader).GetProperty("Item", new[] { typeof(string) });
// list of statements in our dynamic method
var statements = new List<Expression>();
// store instance for setting of properties
ParameterExpression instanceParameter = Expression.Variable(typeof(T));
ParameterExpression sqlDataReaderParameter = Expression.Parameter(typeof(SqlDataReader));
// create and assign new T to variable: var instance = new T();
BinaryExpression createInstance = Expression.Assign(instanceParameter, Expression.New(typeof(T)));
statements.Add(createInstance);
foreach (var property in typeof(T).GetProperties())
{
// instance.MyProperty
MemberExpression getProperty = Expression.Property(instanceParameter, property);
// row[property] -- NOTE: this assumes column names are the same as PropertyInfo names on T
IndexExpression readValue = Expression.MakeIndex(sqlDataReaderParameter, indexerProperty, new[] { Expression.Constant(property.Name) });
// instance.MyProperty = row[property]
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
statements.Add(assignProperty);
}
var returnStatement = instanceParameter;
statements.Add(returnStatement);
var body = Expression.Block(instanceParameter.Type, new[] { instanceParameter }, statements.ToArray());
var lambda = Expression.Lambda<Func<SqlDataReader, T>>(body, sqlDataReaderParameter);
// cache me!
return lambda.Compile();
}
Update:
I have now given up and decided it is not worth it. From the comments below, I got as far as:
if (readValue.Type != property.PropertyType)
{
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(Expression.Call(property.PropertyType, "Parse", null, new Expression[] { Expression.ConvertChecked(readValue, typeof(string)) }), property.PropertyType));
statements.Add(assignProperty);
}
else
{
// instance.MyProperty = row[property]
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
statements.Add(assignProperty);
}
I don't think I was too far off, feel free to finish it and post the answer if you figure it out :)
You could try to fix it by "convert checked" before assigning i.e. using Expression.ConvertChecked on the value instead of Expression.Convert .
Couldn't try it right now but this should take care of the case you describe...
EDIT - as per comment this could be a boxing issue:
In this case you could try using Expression.TypeAs or Expression.Unbox for the conversion or use Expression.Call for calling a method to do the conversion... an example for using Call can be found at http://msdn.microsoft.com/en-us/library/bb349020.aspx
What you're trying to build is actually much more complicated if you want to support 100% of the primitives in .NET and SQL.
If you don't care about some of the edge cases (nullable types, enums, byte arrays, etc), two tips to get you 90% there:
Don't use the indexer on IDataRecord, it returns an object and the boxing/unboxing will kill performance. Instead, notice that IDataRecord has Get[typeName] methods on it. These exist for all .NET primitive types (note: it's GetFloat, not GetSingle, huge annoyance).
You can use IDataRecord.GetFieldType to figure out which Get method you need to call for a given column. Once you have that, you can use Expression.Convert to coerce the DB column type to the target property's type (if they're different). This will fail for some of the edge cases I listed above, for those you need custom logic.
Related
My ultimate goal here is to make a generic version of IQueryable<T>.OrderBy() that takes a string parameter and an optional sort direction. Something like these:
return myList.OrderBy("Property1");
return myList.Orderby("Property1", SortOrder.Descending);
(The use case would be a website passing in a field the list would sort by.)
To that end, I've been trying to come up with a way of creating the following expression:
obj => obj.PropertyName
I've found a few places in StackOverflow that could help me, and they've gotten me quite close (this one in particular). Butt it doesn't quite get me all the way there. Specifically I keep getting the dreaded
Expression of type 'System.Int64' cannot be used for return type 'System.Object' for value types. I thought I could get away with return dynamic here, but that seems to have fallen over. I could do a Convert, but that seems like it should be unnecessary.
My code for generating the property selector is as follows:
public static Expression<Func<T, dynamic>> GeneratePropertySelector<T>(string propertyName)
{
var objectType = typeof(T);
var property = objectType.GetProperty(propertyName);
ParameterExpression arg = Expression.Parameter(objectType, "obj");
MemberExpression propertyExpression = Expression.Property(arg, propertyName);
// Here is the line that dies
var selectorExpression = Expression.Lambda<Func<T, dynamic>>(propertyExpression, new ParameterExpression[] { arg });
return selectorExpression;
}
And then usage inside the extension method implementation would be:
var ordered = myList.OrderBy(GeneratePropertySelector("Property1"));
For a string property, this works fine; for an int property, error.
Does anyone know how to get around this? I would have thought that dynamic would have helped here, but I'm at a loss. And given my use case, I'm trying to avoid something like this:
return myList.Orderby<int>("MyIntProperty");
I'm trying to implement static reflection for all fields in the class.
In other words, I have to create get and set using name for all these fields.
I use the answers on Set field value with Expression tree, and came to the following solution
public class ExpressionSetterGetter
{
public class SetterGetter<T> where T : class
{
public Delegate getter;
public Action<T, object> setter;
}
public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>() where T : class
{
var dic = new Dictionary<string, SetterGetter<T>>();
SetterGetter<T> setterGetter;
var type = typeof(T);
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var fieldInfo in fields)
{
var targetExp = Expression.Parameter(type, "target");
var valueExp = Expression.Parameter(typeof(object), "value");
var fieldExp = Expression.Field(targetExp, fieldInfo);
var assignExp = Expression.Assign(fieldExp, Expression.Convert(valueExp, fieldExp.Type));
var fieldSetter = Expression.Lambda<Action<T, object>>(assignExp, targetExp, valueExp).Compile();
ParameterExpression objParm = Expression.Parameter(type, "obj");
MemberExpression fieldExpr = Expression.Field(objParm, fieldInfo.Name);
var fieldExprConverted = Expression.Convert(fieldExpr, typeof(object));
var fieldGetter = Expression.Lambda(fieldExprConverted, objParm).Compile();
setterGetter = new SetterGetter<T>() { setter = fieldSetter, getter = fieldGetter };
dic.Add(fieldInfo.Name, setterGetter);
}
return dic;
}
}
Now, I have these two issues.
I use type.GetFields(), but MSDN says it is a reflection method.
What means that the compiler doesn't know the type before runtime.
Am I right? If it is correct, what is the reason to use the
expression trees. As far as I know expression trees translate to the
code at compile-time time, what means almost no additional costs.
The same logic. What if I put as a parameter a list with name of
fields what have to be wrapped. In other words, instead of
type.GetFields() I simply put the names of fields as parameters.
public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>(IEnumerable<string> fieldNames)
Obviously, the list can be not known at compile-time. Again, how the CLR will react?
Expression trees' output is not known in compile time, they are compiled at runtime, which is something different. Advantage of using (cached) expression trees compilation is that reflection heavy lifting is performed only once, during the expression construction and compilation. From there, invocation of the resulting delegate is very fast.
In case you are sure the list specifies only the fields that actually exist in your class and you provide only a subset of all the fields, you could, in theory, somewhat reduce the performance impact of the reflection. But you should keep in mind that you will still need the FieldInfo instances for each of them which could only be retrieved using reflection. So the overall price of invoking GetField for every known field will probably be even higher than just calling GetFields for all of them.
The easiest way to set fields value in compile time is converting your private fields to public properties. Then, you can set them as you wish.
And this is not a joke on you, it's an explanation of the difference - C# doesn't allow setting fields from outside, except using reflection API's. And those API's designed for runtime, not for compile time.
If you'd like to bend the rules and produce such a code at compilation time (precisely, at post-compilation time), you should use some third party library such as PostSharp or Fody.
And that's the end of the story, so long as you are using C# in it's current or one of the previous versions.
From this question I asked 5 minutes ago, it's clear that the following code throws an exception, stating that
Unhandled Exception:
System.InvalidOperationException: The
binary operator Equal is not defined
for the types
'System.Nullable`1[System.Int32]' and
'System.Int32'.
Code
public static void GetResultCollection<T>() {
AccrualTrackingEntities db = new AccrualTrackingEntities();
var result = db.CreateQuery<T>(String.Format("[{0}]", typeof(T).Name + "s"));
int? ItemTypeValue = 1;
var param = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(param, "ProcInstId"),
Expression.Constant(ItemTypeValue)),
param);
var list = result.Where(lambda).ToList();
}
This code, however, with the type explicitly listed in Expression.Constant does work
class Program {
public static void GetResultCollection<T>() {
AccrualTrackingEntities db = new AccrualTrackingEntities();
var result = db.CreateQuery<T>(String.Format("[{0}]", typeof(T).Name + "s"));
int? ItemTypeValue = 1;
var param = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(param, "ProcInstId"),
Expression.Constant(ItemTypeValue, typeof(int?))),
param);
var list = result.Where(lambda).ToList();
}
The question is, why is Expression.Constant not able to convert implicitly from int? to ... int?
Expression trees work at a lower level to normal source code - you can think of them as working at the level of the output of the compiler rather than the input. So while there's an implicit conversion from int to int? in C#, that conversion has to be represented in IL whenever the compiler uses it for a normal method... so it also has to be present in an expression tree representation.
Having said that, your example is somewhat unclear, given that you're trying to use an int (namely ItemTypeValue.Value) as a value for an int? constant, and we don't know what the type of the ItemType property is either.
A short but complete example of what you'd expect to work would really help.
EDIT: Okay, I think I'm with you now. The problem is that if you use
int? foo = 1;
Expression.Constant(foo);
then that calls Expression.Constant(object) which boxes the value of foo. At that point, Expression.Constant can't tell it was originally an int?, because it's now a boxed int. That's just the way .NET boxing works:
int? foo = 1;
object o = foo;
Console.WriteLine(o.GetType()); // Prints System.Int32
That overload of Expression.Constant determines the overall type of the expression from the value that it's given - so it creates an int expression, whereas you really want an int? expression.
In order to maintain the type information properly, you have to use the overload which allows you to specify the type:
int? foo = 1;
Expression.Constant(foo, typeof(int?));
It's still not entirely clear from your question which code works and which doesn't, but hopefully that'll help...
For various reasons I'm constructing a C# lambda dynamically using the expression tree facilities. e.g. I can make a Func<string,bool> at runtime as shown in the following snippet.
public static bool myMethod( object obj ) { … }
// Construct a Func<string,bool>
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (string))};
var callMyMethod = Expression.Call(myMethod, lambdaParams);
var lambda = Expression.Lambda(typeof(Func<string,bool>), callMyMethod, lambdaParams);
var del = (Func<string,bool>)lambda.Compile();
del("foo"); // works
However if I use the same code to try to make a Func<int,bool> or a Func<DateTime,bool> it blows up where indicated with the following strange exception:
// Construct a Func<DateTime,bool> or perhaps a struct type fails... why?
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (DateTime))};
var callMyMethod = Expression.Call(myMethod, lambdaParams); // Blows up here…
System.ArgumentException: Expression of type 'System.DateTime' cannot be used for parameter of type 'System.Object' of method 'Boolean myMethod(System.Object)'
So, string works and List<string> works but int32 does not work nor does DateTime. What is going on? I don't know how the deep internals of C# work but I am guessing it's due to int really being handled as a primitive and maybe DateTime (being a struct) as well...
Any help with this would be greatly appreciated.
thanks,
Pat
As I understand it, Expression.Call doesn't perform auto-boxing of value-type arguments. I'm unable to find any documentation to that effect, but it is mentioned on this forum page.
One workaround would be to explicitly do the boxing conversion in the expression with Expression.TypeAs.
Creates a UnaryExpression that
represents an explicit reference or
boxing conversion where null is
supplied if the conversion fails.
In your case, this should work:
var boxedParams = lambdaParams.Select(p => Expression.TypeAs(p, typeof(object)))
.ToArray();
var callMyMethod = Expression.Call(myMethod, boxedParams);
(You don't need the fancy lambdas if there's only one parameter)
Depending on the real usage, you may have to check if the boxing conversion is necessary depending on whether the type(s) in question is(are) value-type(s).
Check this out: you have to box the DateTime, since DateTime isnt' a reference type!
// Construct a Func<DateTime,bool>
var myMethod = typeof(Program).GetMethod("myMethod");
var param = Expression.Parameter(typeof(DateTime));
var boxy = Expression.TypeAs(param, typeof(object));
var callMyMethod = Expression.Call(myMethod, boxy);
var lambda = Expression.Lambda(typeof(Func<DateTime, bool>), callMyMethod, new ParameterExpression[] { param });
var del = (Func<DateTime,bool>)lambda.Compile();
del(DateTime.Now); // works
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).