Yesterday, I asked yesterday about how to read the properties of an anonymous object and write them to the private fields of the class. The problem is resolved. Here is a short story:
I have some data in json format. I deserialize them to ExpandoObject and pass them as IDictionary<string, object> to the method. It works great except for the Int32 properties. It seems they are changing to Int64 , where? I dont know.
Here is the method again:
private Func<IDictionary<string, object>, dynamic> MakeCreator( Type type, Expression ctor, IEnumerable<PropertyToFieldMapper> maps) { var list = new List<Expression>(); var vList = new List<ParameterExpression>(); // creating new target var targetVariable = Expression.Variable(type, "targetVariable"); vList.Add(targetVariable); list.Add(Expression.Assign(targetVariable, Expression.Convert(ctor, type))); // accessing source var sourceType = typeof(IDictionary<string, object>); var sourceParameter = Expression.Parameter(sourceType, "sourceParameter"); // calling source ContainsKey(string) method var containsKeyMethodInfo = sourceType.GetMethod("ContainsKey", new[] { typeof(string) }); var accessSourceIndexerProp = sourceType.GetProperty("Item"); var accessSourceIndexerInfo = accessSourceIndexerProp.GetGetMethod(); // itrate over writers and add their Call to block var containsKeyMethodArgument = Expression.Variable(typeof(string), "containsKeyMethodArgument"); vList.Add(containsKeyMethodArgument); foreach (var map in maps) { list.Add(Expression.Assign(containsKeyMethodArgument, Expression.Constant(map.Property.Name))); var containsKeyMethodCall = Expression.Call(sourceParameter, containsKeyMethodInfo, new Expression[] { containsKeyMethodArgument }); // creating writer var sourceValue = Expression.Call(sourceParameter, accessSourceIndexerInfo, new Expression[] { containsKeyMethodArgument }); var setterInfo = map.Field.GetType().GetMethod("SetValue", new[] { typeof(object), typeof(object) }); var setterCall = Expression.Call(Expression.Constant(map.Field), setterInfo, new Expression[] { Expression.Convert(targetVariable, typeof(object)), Expression.Convert(sourceValue, typeof(object)) }); Console.WriteLine(Expression.Lambda(setterCall)); list.Add(Expression.IfThen(containsKeyMethodCall, setterCall)); } list.Add(targetVariable); var block = Expression.Block(vList, list); var lambda = Expression.Lambda<Func<IDictionary<string, object>, dynamic>>( block, new[] { sourceParameter } ); return lambda.Compile(); }
If we have it
public class Person { public int Age { get; set; } public string Name { get; set; } }
and use this object
var data = new { Name = "Amiry", Age = 20 };
to initialize an instance of Person using the above method, this error occurs:
An object of type 'System.Int64' cannot be converted to type 'System.Int32'.
But if we change the Age property to:
public long Age { get; set; }
every thing looks great and the method works great. I am completely confused why this is happening. Do you have any ideas?