I'm storing an update operation as thus:
class Update
{
public Expression MemberExpression { get; set; }
public Type FieldType { get; set; }
public object NewValue { get; set; }
}
For example:
var myUpdate = new Update
{
MemberExpression = (MyType o) => o.LastModified,
FieldType = typeof(DateTime?),
NewValue = (DateTime?)DateTime.Now
}
Then I'm trying to apply this update later (simplified):
var lambda = myUpdate.MemberExpression as LambdaExpression;
var memberExpr = lambda.Body as MemberExpression;
var prop = memberExpr.Member as PropertyInfo;
prop.SetValue(item, myUpdate.Value);
However, myUpdate.Value
is a DateTime
, not a DateTime?
. This is because when you cast a nullable to an object
, it either becomes null
or boxes the value type.
Since (DateTime?)myUpdate.Value
would work to get it back to the correct type, I tried to simulate this compile-time construct using Convert.ChangeType
. However, it says that casting from DateTime
to DateTime?
is not possible.
What approach can I use here to get the object back into its original type?
Is there any way to store a nullable types, regular structs and regular objects in a single field, and get the exact thing stored into it back again?
If you know the type of your Expression when you create myUpdate, SetInfo()
will properly set your data, even if boxing/unboxing.
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();
}
This properly outputs a DateTime value corresponding to when it was created without an exception.
Maybe you can use a generic class?
class Update<TField>
{
public Expression<Func<MyType, TField>> MemberExpression { get; set; }
public TField NewValue { get; set; }
}
Not sure if you can just use a plain Func<MyType, TField>
delegate instead of the expression tree, for your use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With