【问题标题】:System.InvalidCastException: 'Unable to cast object of type 'System.String' to type 'Newtonsoft.Json.Linq.JToken'.'System.InvalidCastException:'无法将'System.String'类型的对象转换为'Newtonsoft.Json.Linq.JToken'类型。'
【发布时间】:2020-05-16 05:52:44
【问题描述】:

如果我运行代码:

    object myObject = "abc";
    JToken jToken = (JToken)myObject;

它编译得很好,但它会抛出一个神秘的异常标题。这是神秘的,因为可以通过以下编译和正确运行将表单 String 转换为 JToken:

    String mystring = "abc";
    JToken jToken2 = (JToken)mystring;

所以我很好奇为什么会这样?

当然,上面的例子有点傻,但也许能理解我为什么问这个是因为在下面的情况下也会产生同样的错误。

class Program
    public static JToken apply_function(Delegate function, object[] arglist)
    {
        return (JToken)function.DynamicInvoke(arglist);
    }

    static void Main(string[] args)
    {
        Func<string> hello = () => { return "hello world!"; };
        Console.WriteLine(apply_function(hello, new object[0]));
    }
}

在想要使用apply_function的实际情况中,是我无法控制返回类型或提供给apply_function的Delegate的参数类型的情况。我唯一的保证是,Delegate 将是一个函数,它返回可转换为 JToken 的东西。

【问题讨论】:

  • 不要将多个内容放在一行中。返回、强制转换和函数调用是三件事,每件事都会给你编译错误。将代码压缩到一行中的唯一代价就是调试它的时间很长。使用临时/局部变量将代码拆分为多行。不要担心性能 - 在调试构建之外,各种优化会减少未充分利用的变量。

标签: c# dynamic casting


【解决方案1】:

这不是真正的演员表,而是conversion。可以看到in the docs,Json.NET 定义了从string 到JToken 的转换。

您示例中的静态类型是 object - 没有定义从 object 到 JToken 的转换。

在我看来,您应该尝试使用 JToken.FromObject。

【讨论】:

  • JToken.FromObject 确实解决了我的问题。仍然让我感到困惑的是,当问题出在静态类型时,为什么错误消息会显示动态类型。还有,为什么静态类型有问题不会产生编译器错误。
  • @M.D.该错误显示string 类型,因为它尝试进行强制转换,而不是在运行时类型上的转换。您不会收到编译错误,因为只要所述对象引用JToken 的实例,就可以将object 转换为JToken。
【解决方案2】:

这样做的原因:

string mystring = "abc";
JToken jToken2 = (JToken)mystring;

JToken 是否有来自string 的显式转换运算符。

显式转换运算符不尊重继承层次结构,就像标准转换一样,这就是为什么它不适用于object。

JToken 具有广泛的用户定义转换,但它并不适用于所有类型,因为您似乎在 apply_function 中很喜欢。

另一种选择是JToken.FromObject:

public static JToken apply_function(Delegate function, object[] arglist)
{
    return JToken.FromObject(function.DynamicInvoke(arglist));
}

【讨论】:

    【解决方案3】:

    Charles Mager 的回答让我意识到静态类型是问题所在,因此:

        public static JToken apply_function(Delegate function, object[] arglist)
        {
            return (dynamic)function.DynamicInvoke(arglist);
        }
    

    也能解决问题。我想如果想要 apply_function 返回一个 JToken JToken.FromObject 是更好的函数。但并不是每个类都可能有一个静态的FromObject 函数。

    【讨论】:

    • 不,不要使用dynamic,这只会将错误推迟到运行时。不是每个类都需要FromObject 方法;在JToken 上定义。
    • @JohnathanBarclay 这已经是一个运行时错误。附:您是否真的尝试使用额外的动态转换来运行它?因为对我来说它编译并运行良好。
    • 是的,它适用于这个特定示例,因为有来自 string 的转换,但试试这个:Func&lt;List&lt;string&gt;&gt; hello = () =&gt; { return new List&lt;string&gt; { "hello world!" }; };。它编译得很好,但运行时异常。 JToken.FromObject 也不例外。
    • 通过使用dynamic,apply_function 仅适用于已定义转换为JToken 的类型,其他类型将给您一个例外。
    • 是的,我意识到我的答案仅适用于已定义转换的类型。这就是为什么我说FromObject 是JToken 的最佳解决方案。但是如果有人(可能是我)想要一个public static TypeWithoutFromObject apply_function(...) 函数,那么别无选择,只能使用转换,而动态关键字可以解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 2012-09-07
    • 2014-03-14
    • 2017-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多