表达式以转换数值:System.InvalidCastException:>无法将类型为'System.Int32'的对象转换为类型为'System.Int64'

问题描述 投票:1回答:1

我正在尝试创建一个表达式来转换一些数字值。这是我尝试过的:

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?预先感谢。

c# lambda .net-core casting expression-trees
1个回答
0
投票

以下内容利用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());
}
© www.soinside.com 2019 - 2024. All rights reserved.