简体   繁体   English

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

[英]Why is casting a dynamic of type object to object throwing a null reference exception?

I have the following function: 我有以下功能:

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

When I call it in the following way, 当我以以下方式调用它时,

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

(T)boxed throws a null reference exception. (T)boxed引发空引用异常。

Any other type I put in there other than "object", it works perfectly fine. 除了“对象”之外,我在其中输入的任何其他类型的效果都很好。
Any ideas what this is, and why it's throwing the exception? 任何想法,这是什么,以及为什么引发异常?

Edit: The reason why I use dynamic is to avoid exception when converting types, for example: 编辑:我使用动态的原因是为了避免在转换类型时出现异常,例如:

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

I agree with the other answerers who say that this looks like a bug. 我同意其他回答者的意见,他们说这看起来像个错误。 Specifically it appears to be a bug in C# runtime binding layer, though I have not investigated it thoroughly. 具体来说,它似乎是C#运行时绑定层中的错误,尽管我尚未对其进行彻底研究。

I apologize for the error. 对于错误,我深表歉意。 I'll report it to the C# 5 testing team and we'll see if it has already been reported and fixed in C# 5. (It reproduces in the recent beta release, so it is unlikely that it has already been reported and fixed.) If not, a fix is unlikely to make it into the final release. 我将其报告给C#5测试团队,我们将查看它是否已在C#5中进行了报告和修复。(它在最近的beta版本中复制,因此不太可能已经在报告和修复中。 )如果没有,则修复程序不可能使其最终发行。 In that case we'll consider it for a possible servicing release. 在这种情况下,我们将考虑将其作为可能的维修版本。

Thanks for bringing this to our attention. 谢谢让我们注意到这个。 If you feel like entering a Connect issue to track it, feel free to do so and please include a link to this StackOverflow question. 如果您想输入一个连接问题来跟踪它,请随时这样做,并请提供指向此StackOverflow问题的链接。 If you don't, no problem; 如果不这样做,没问题; the test team will know about it either way. 测试团队会以任何一种方式知道它。

This is an issue with how dynamic works - the runtime binder has an issue with conversions from System.Object , but in practice, is really not an issue. 这是动态工作方式的一个问题-运行时绑定程序遇到了System.Object转换问题,但实际上并不是问题。

I suspect this is because dynamic , at runtime, is itself always System.Object . 我怀疑这是因为在运行时dynamic本身始终是 System.Object The C# Language Spec in 4.7 states: "The type dynamic is indistinguishable from object at run-time." 4.7中的C#语言规范指出:“动态类型在运行时与对象没有区别。” As such, any object used as dynamic is just stored as an object. 这样,用作动态对象的任何对象都仅存储为对象。

When you put an actual instance of System.Object into a dynamic, something is occuring within the runtime binding resolution which causes a null reference exception. 当您将System.Object的实际实例放入动态库时,运行时绑定解析中发生了某些事情,这导致空引用异常。

However, any other type that isn't System.Object works - even reference types and the like, without flaws. 但是,不是System.Object 任何其他类型都可以使用-甚至引用类型等也没有缺陷。 As such, this should provide you the proper behavior, since there really are no reasons to create an instance of System.Object itself which would be passed around - you'd always want some subclass with other type information. 这样,这应该为您提供适当的行为,因为实际上没有理由创建将被传递的System.Object本身的实例-您始终希望某些子类具有其他类型信息。

As soon as you use any "real" type, this works fine. 只要您使用任何“真实”类型,就可以正常工作。 For exmaple, the following works, even though it's passed and treated as 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();
    }
}

This is really strange behavior, and it indeed looks like a bug in the implementation of dynamic . 这确实是奇怪的行为,并且确实看起来像是dynamic实施中的错误。 I discovered that this variation does not throw an exception and indeed returns the object: 我发现此变体不会引发异常,并且确实会返回该对象:

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

Note that I had to add a generic constraint in the method signature because the as operator only works if T is a reference type. 请注意,我必须在方法签名中添加一个通用约束,因为as运算符仅在T是引用类型时才起作用。

If you are looking for a workaround, you could use this (and I know it's ugly): 如果您正在寻找解决方法,则可以使用此方法(我知道这很丑陋):

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

It has something to do with the dynamic keyword. 它与dynamic关键字有关。 If I change the type to T for boxed it works. 如果我将类型更改为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;

    }

Is there a particular reason that you are using dynamic? 您使用动态有什么特殊原因吗? You really don't need it in this case as you know what the type is ahead of time. 在这种情况下,您真的不需要它,因为您提前知道了什么类型。 If you look, in your version the type of boxed isn't object but it is dynamic{object} which could be the issue when trying to cast to object. 如果您看,在您的版本中,装箱的类型不是对象,而是动态的{object},这可能是尝试转换为对象时遇到的问题。 If you look at this version that I posted, you get a type of object and no errors. 如果您查看我发布的此版本,则会得到一种对象,并且没有错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM