I am trying to use C# object initializer syntax with LINQ Expressions trees and I used type conversions (i.e. Expression.Convert) so I shouldn't get invalid cast exceptions for simple type conversions (i.e. int to double) but I still get invalid cast exceptions.
Error:
Unhandled exception. System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.Double'.
at lambda_method1(Closure, Dictionary`2)
at Program.Main(String[] args) in
Lambda expression I am generating dynamically:
Dictionary<string, object> $var0) => new Foo() {
Name = (string)$var0["Name"],
Salary = (double)$var0["Salary"]
}
Code:
internal class Program
{
public static void Main(string[] args)
{
var foo = (Foo)InstantiateAndInitializeType(typeof(Foo))(new Dictionary<string, object>
{
["Name"] = "foobar",
["Age"] = 12,
["Salary"] = 20
});
Console.WriteLine(JsonConvert.SerializeObject(foo, Formatting.Indented));
}
public static Func<Dictionary<string, object>, object> InstantiateAndInitializeType(Type type)
{
var dictArg = Expression.Parameter(typeof(Dictionary<string, object>));
var body = Expression.MemberInit(Expression.New(typeof(Foo)), typeof(Foo)
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)
.Where(x => x.GetCustomAttribute<RequiredMemberAttribute>() != null)
.Select(x => Expression.Bind(x, Expression.Convert(Expression.Property(dictArg, "Item", Expression.Constant(x.Name)), x.PropertyType))));
var lambdaExpr = Expression.Lambda<Func<Dictionary<string, object>, object>>(body, dictArg);
var func = lambdaExpr.Compile();
return func;
}
}
class Foo
{
public required string Name { get; set; }
public double Age { get; set; }
public required double Salary { get; set; }
}
Expression.Convertfor this exact reason. Why is it not working?double d = (double)(object)32;Expression.Convertis equivalent toConvert.ChangeType. So how to fix this code?Expression.Convertis a typecast and the C# documentation for Explicit Conversions that are Unboxing Conversions (from reference type (object) to value type (double)) states that only when the reference is to a boxed value of the correct type. Since the value is actually anInt32, the conversion fails at runtime.