我正在尝试创建一个表达式来转换一些数字值。这是我尝试过的:
public object ConvertValue(object value, Type targetType) {
var parameter = Expression.Parameter(typeof(object), "p"); // "p"
var convert = Expression.Convert(parameter, targetType); // Convert(p, Int64)
var targetConvert = Expression.Convert(convert, typeof(object)); // Convert(Convert(p, Int64), Object)
var lambda = Expression.Lambda<Func<object,object>>(targetConvert, parameter); // p => Convert(Convert(p, Int64), Object)
var method = lambda.Compile();
var result = method(value); // HERE I GET THE ERROR!
return result;
}
但是当我调用它时,就像这个简单的测试:
[Fact]
public void TestConvert() {
var result = ConvertValue(23, typeof(long));
Assert.Equal(typeof(long), result.GetType());
}
我收到错误:
System.Reflection.TargetInvocationException:引发了异常通过调用的目标。 ---> System.InvalidCastException:无法将类型为“ System.Int32”的对象转换为类型为“ System.Int64”的对象。在lambda_method(Closure,Object)bla bla bla ...
[任何想法,这里发生了什么,什么Int32
无法转换为Int64
?预先感谢。
以下内容利用Convert.ChangeType
来提供更多的转换灵活性。
代码注释记录了正在执行的操作。
public object ConvertValue(object value, Type targetType){
var valueType = value.GetType();
// Func<TValue,TTarget>
var delegateType = typeof(Func<,>).MakeGenericType(valueType, targetType);
var convert = typeof(Convert).GetMethod("ChangeType", new[] { typeof(object), typeof(Type) });
// TValue p
var parameter = Expression.Parameter(valueType, "p");
// Convert.ChangeType(Convert(p), targetType);
var changeType = Expression.Call(convert, Expression.Convert(parameter, typeof(object)), Expression.Constant(targetType));
// (TTarget)Convert.ChangeType(Convert(p), targetType);
var body = Expression.Convert(changeType, targetType);
//Func<TValue,TTarget> = TValue p => (TTarget)Convert.ChangeType(Convert(p), targetType);
var lambda = Expression.Lambda(delegateType, body, parameter);
var method = lambda.Compile();
var result = method.DynamicInvoke(value);
return result;
}
以下基本测试通过后全部通过
[TestMethod]
public void Should_Convert_Int_To_Long() {
var expected = typeof(long);
var actual = ConvertValue(23, expected);
Assert.AreEqual(expected, actual.GetType());
}
[TestMethod]
public void Should_Convert_Long_To_Int() {
var expected = typeof(int);
var actual = ConvertValue((long)23, expected);
Assert.AreEqual(expected, actual.GetType());
}
[TestMethod]
public void Should_Convert_String_To_Long() {
var expected = typeof(long);
var actual = ConvertValue("23", expected);
Assert.AreEqual(expected, actual.GetType());
}
[TestMethod]
public void Should_Convert_String_To_Int() {
var expected = typeof(int);
var actual = ConvertValue("23", expected);
Assert.AreEqual(expected, actual.GetType());
}