我正在存储更新操作:
class Update
{
public Expression MemberExpression { get; set; }
public Type FieldType { get; set; }
public object NewValue { get; set; }
}
例如:
var myUpdate = new Update
{
MemberExpression = (MyType o) => o.LastModified,
FieldType = typeof(DateTime?),
NewValue = (DateTime?)DateTime.Now
}
然后我试图稍后(简化)应用此更新:
var lambda = myUpdate.MemberExpression as LambdaExpression;
var memberExpr = lambda.Body as MemberExpression;
var prop = memberExpr.Member as PropertyInfo;
prop.SetValue(item, myUpdate.Value);
但是,myUpdate.Value
是DateTime
,而不是DateTime?
。这是因为当您将可归结为object
时,它会变为null
或将值类型化为空。
由于(DateTime?)myUpdate.Value
可以使其恢复到正确的类型,我尝试使用Convert.ChangeType
来模拟这个编译时构造。但是,它表示无法从DateTime
投射到DateTime?
。
我可以在这里使用什么方法将对象恢复为原始类型?
有没有办法在一个字段中存储可以为空的类型,常规结构和常规对象,然后再将相同的内容存储回来?
答案 0 :(得分:1)
也许你可以使用泛型类?
class Update<TField>
{
public Expression<Func<MyType, TField>> MemberExpression { get; set; }
public TField NewValue { get; set; }
}
不确定是否可以使用普通Func<MyType, TField>
委托代替表达式树,供您使用。
答案 1 :(得分:1)
如果您在创建myUpdate时知道Expression的类型,SetInfo()
将正确设置您的数据,即使装箱/取消装箱也是如此。
public class Update
{
public Expression MemberExpression { get; set; }
public Type ClassType { get; set; }
public object NewValue { get; set; }
}
public class MyType
{
public DateTime? LastModified { get; set; }
}
void Main()
{
var myUpdate = new Update
{
MemberExpression =
(Expression<Func<MyType, DateTime?>>)((MyType o) => o.LastModified),
ClassType = typeof(MyType),
NewValue = DateTime.Now
};
// At a later point where we do not want to instantiate via strong typing
var item = Activator.CreateInstance(myUpdate.ClassType);
var lambda = myUpdate.MemberExpression as LambdaExpression;
var memberExpr = lambda.Body as MemberExpression;
var prop = memberExpr.Member as PropertyInfo;
prop.SetValue(item, myUpdate.NewValue);
item.Dump();
}
这正确输出了一个DateTime值,该值对应于创建它时没有例外。
答案 2 :(得分:0)
我能够解决使用表达式而且没有反射:
var lambda = update.MemberExpression as LambdaExpression;
var memberExpr = lambda.Body as MemberExpression;
if (memberExpr == null)
{
throw new NotSupportedException("Field expression must be a member expression");
}
// do a cast - this ensures nullable types work, for instance
var cast = Expression.Convert(Expression.Constant(update.Value), update.FieldType);
// assign the target member with the cast value
var assignment = Expression.Assign(memberExpr, cast);
// build a new lambda, no return type, which does the assignment
var newLambda = Expression.Lambda(typeof(Action<T>), assignment, lambda.Parameters[0]);
// compile to something we can invoke, and invoke
var compiled = (Action<T>)newLambda.Compile();
compiled(item);
瞧,该项目已被修改:)