为什么将类型对象的动态类型转换为抛出空引用异常的对象?

时间:2012-03-29 18:53:39

标签: c# .net dynamic nullreferenceexception

我有以下功能:

public static T TryGetArrayValue<T>(object[] array_, int index_)
{
    ... //some checking goes up here not relevant to question

    dynamic boxed = array_[index_];
    return (T)boxed;
}

当我以下列方式打电话时,

object a = new object();
object v = TUtils.TryGetArrayValue<object>(new object[] { a }, 0);

(T)boxed抛出空引用异常。

除了“对象”之外,我放在那里的任何其他类型,它完全正常 任何想法是什么,为什么它抛出异常?

编辑: 我使用dynamic的原因是为了避免在转换类型时出现异常,例如:

double a = 123;
int v = TUtils.TryGetArrayValue<int>(new object[] { a }, 0);

4 个答案:

答案 0 :(得分:43)

我同意其他回答说这看起来像个错误的回答者。具体来说,它似乎是C#运行时绑定层中的一个错误,但我没有彻底调查它。

我为错误道歉。我将它报告给C#5测试团队,我们将看看它是否已经在C#5中报告和修复。(它在最近的beta版本中重现,所以它不太可能已经被报告和修复。 )如果没有,修复不太可能进入最终版本。在这种情况下,我们会考虑将其用于可能的服务发布。

感谢您引起我们的注意。如果您希望entering a Connect issue跟踪它,请随意这样做,并请包含此StackOverflow问题的链接。如果你不这样做,没问题;测试团队会以任何方式了解它。

答案 1 :(得分:14)

这是动态工作原理的一个问题 - 运行时绑定程序存在来自System.Object的转换问题,但在实践中,确实不是问题。

我怀疑这是因为dynamic在运行时本身总是 System.Object。 4.7中的C#语言规范:“动态类型在运行时与对象无法区分。”因此,任何用作动态的对象都只是作为对象存储。

当您将System.Object的实际实例放入动态时,运行时绑定解析中会出现一些导致空引用异常的内容。

然而,不是System.Object的任何其他类型都可以工作 - 甚至是引用类型等,没有缺陷。因此,这应该为您提供正确的行为,因为实际上没有理由创建一个System.Object本身的实例,它将被传递 - 您总是希望某个子类具有其他类型信息。

只要您使用任何“真实”类型,这都可以。例如,以下工作,即使它已被传递并视为Object

public class Program
{
    public static T TryGetArrayValue<T>(object[] array_, int index_)
    {

        dynamic boxed = array_[index_];
        return (T)boxed;
    }

    private static void Main()
    {
        int p = 3;
        object a = p;
        var objects = new[] { a, 4.5 };

        // This works now, since the object is pointing to a class instance
        object v = TryGetArrayValue<object>(objects, 0);
        Console.WriteLine(v);

        // These both also work fine...
        double d = TryGetArrayValue<double>(objects, 1);
        Console.WriteLine(d);
        // Even the "automatic" int conversion works now
        int i = TryGetArrayValue<int>(objects, 1);
        Console.WriteLine(i);
        Console.ReadKey();
    }
}

答案 2 :(得分:6)

这是一种非常奇怪的行为,它确实看起来像dynamic的实现中的一个错误。我发现这种变化不会引发异常并确实返回对象:

public static T TryGetArrayValue<T>(object[] array, int index) where T : class
{
    dynamic boxed = array[index];
    return boxed as T;
}

请注意,我必须在方法签名中添加通用约束,因为as运算符仅在T是引用类型时才有效。

如果您正在寻找一种解决方法,您可以使用它(我知道它很难看):

public static T TryGetArrayValue<T>(object[] array, int index)
{
    dynamic boxed = array[index];

    if (typeof(T) == typeof(object))
        return (T)(boxed as object);

    return (T)boxed;
}

答案 3 :(得分:2)

它与dynamic关键字有关。如果我将类型更改为T为盒装,则可以正常工作。

    static void Main(string[] args)
    {
        object a = new object();
        object v = TryGetArrayValue<object>(new object[] { a }, 0);

        Console.ReadLine();
    }

    public static T TryGetArrayValue<T>(object[] array_, int index_)
    {

            T boxed = (T)array_[index_];
            return boxed;

    }

您使用动态是否有特殊原因?在这种情况下你真的不需要它,因为你知道这种类型是提前的。如果你看一下,在你的版本中,盒装的类型不是对象,而是动态{object},这可能是试图转换为对象时的问题。如果你看一下我发布的这个版本,就会得到一种对象而且没有错误。