我昨天在这里提出了一个与读取匿名对象的属性并将其写入类的私有字段相关的问题。问题已经解决。以下是简短的故事:
我有一些以json格式存储的数据。我将它们反序列化为
以下是该方法:
如果我们有这个:
我有一些以json格式存储的数据。我将它们反序列化为
ExpandoObject
,并将它们作为IDictionary<string, object>
传递给方法。除了Int32
属性之外,它都可以正常工作。似乎它们变成了Int64
,但我不知道原因。以下是该方法:
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();
}
如果我们有这个:
public class Person {
public int Age { get; set; }
public string Name { get; set; }
}
创建类,并使用该对象
var data = new { Name = "Amiry", Age = 20 };
使用以上方法初始化Person
实例时,会出现以下错误:
无法将类型为“System.Int64”的对象转换为类型“System.Int32”。
但如果我们将Age
属性改为:
public long Age { get; set; }
一切看起来都很好,方法运行得很完美。我完全困惑于为什么会发生这种情况。你有任何想法吗?
Dictionary
/sourceParameter
开始。它里面有long
吗?如果有,那么这个映射代码与问题无关。 - Andrey ShchekinsetterInfo
进行设置。完整的解决方案在这里。如果你想的话,请看一下。 - amiry jdint
,因为它基于字段类型。但在实际字典中可能是long
。 - Andrey Shchekin