C# 为什么将动态类型的对象强制转换为对象会引发空引用异常?

C# 为什么将动态类型的对象强制转换为对象会引发空引用异常?,c#,.net,dynamic,nullreferenceexception,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; } 它与dynamic关键字有关。如果我将boxed的类型更改为T,它会工作 stati

我有以下功能:

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;
}

它与dynamic关键字有关。如果我将boxed的类型更改为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;

    }
static void Main(字符串[]args)
{
对象a=新对象();
对象v=tryGetAryValue(新对象[]{a},0);
Console.ReadLine();
}
公共静态T TryGetArray值(对象[]数组,整数索引)
{
T装箱=(T)数组[索引];
盒装退货;
}

您使用dynamic有什么特别的原因吗?在这种情况下,您确实不需要它,因为您提前知道类型。如果您看一下,在您的版本中,boxed的类型不是object,而是dynamic{object},这可能是尝试强制转换到object时的问题。如果你看看我发布的这个版本,你会得到一种类型的对象,没有错误。

这是一种非常奇怪的行为,它看起来确实像是
动态
实现中的一个bug。我发现此变体不会引发异常,而是返回对象:

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

这是一个动态工作方式的问题-运行时绑定器在从
System.Object
转换时存在问题,但实际上,这并不是一个问题

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

当您将
System.Object
的实际实例放入动态中时,运行时绑定解析中发生了某种情况,从而导致空引用异常

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

只要您使用任何“真实”类型,它就可以正常工作。对于exmaple,即使它被传递并作为
对象处理,以下操作仍然有效:

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();
    }
}
公共类程序
{
公共静态T TryGetArray值(对象[]数组,整数索引)
{
动态装箱=数组u[索引uz];
返回(T)装箱;
}
私有静态void Main()
{
int p=3;
对象a=p;
var objects=new[]{a,4.5};
//现在可以了,因为对象指向类实例
对象v=tryGetAryValue(对象,0);
控制台写入线(v);
//这两个都很好用。。。
双d=tryGetAryValue(对象,1);
控制台写入线(d);
//即使是“自动”整数转换现在也可以工作了
int i=tryGetAryValue(对象,1);
控制台写入线(i);
Console.ReadKey();
}
}

我同意其他回答者的说法,他们说这看起来像一个bug。具体来说,这似乎是C#运行时绑定层中的一个bug,尽管我还没有对它进行彻底的研究

我为这个错误道歉。我会把它报告给C#5测试团队,我们会看看它是否已经在C#5中报告和修复。(它在最近的beta版本中复制,因此它不太可能已经被报告和修复。)如果没有,修复不太可能进入最终版本。在这种情况下,我们会考虑一个可能的服务版本。< /P>
谢谢你让我们注意到这一点。如果你想跟踪它,请随时这样做,并请包括一个链接到这个问题。如果你没有,没问题;测试团队无论如何都会知道的。

在强制执行之前,检查
装箱的
是否为空。这可能是
动态
实现方式中的错误。现在检查4.5中是否有此重新编程。重新编程-它看起来确实像是处理<代码>动态的错误-问题是有效的+1-似乎只有在转换为泛型类型时才重新编程。是的,我有一个使用动态的用例,因为我想这样做:双a=10923049;intv=TUtils.tryGetAryValue(新对象[]{a},0);使用dynamic可以帮助我从不同的兼容类型执行强制转换。否则它会抛出一个异常。@bedo使用一个名为tryGetAryValue的方法,我希望它能够失败。看到你的意图真让我畏缩!虽然我非常喜欢静态类型和编译类型检查,但不幸的是,我也需要它来处理原语。也许我可以将对象作为特例处理,而不在返回时强制转换。如果您尝试使用'tryGetaryValue(…)@bedo,这甚至不会编译-我扩展了我的答案,以展示如何通过使用
as
关键字来解决此问题。是的,这是有效的。我认为处理这个物体是一种特殊情况。我只是很好奇为什么它会抛出异常。考虑到传入一个简单对象的可能性很小(我不打算传入任何用于同步的对象),我可以接受它抛出null ref异常并用注释注释它。@bedo我不太明白它为什么会在object中失败,但正如我所说的,在实践中,这至少不重要;)我能因为发现了这只虫子而获得荣誉奖吗我刚刚把另一个问题标为这个问题的副本。是否有报告连接错误?如果是这样的话,是否有一个可以跟踪状态的链接?@DStanley:我在2012年向测试团队提到过它,但我完全不记得这个问题是如何被分类的,对不起,不用担心;只是看起来很奇怪,很好奇它是否被修复了。在Connect上查找报告的bug是一项我尚未掌握的技能。在.NETCore中仍然存在。
public static T TryGetArrayValue<T>(object[] array, int index) where T : class
{
    dynamic boxed = array[index];
    return boxed 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;
}
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();
    }
}