提问人:bedo 提问时间:3/30/2012 最后编辑:bedo 更新时间:3/30/2012 访问量:3207
为什么将对象类型的动态转换为对象会引发空引用异常?
Why is casting a dynamic of type object to object throwing a null reference exception?
问:
我有以下功能:
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
引发 null 引用异常。
除了“对象”之外,我放在那里的任何其他类型,它都工作得很好。
知道这是什么,为什么它会抛出异常吗?
编辑: 我之所以使用dynamic,是为了避免在转换类型时出现异常,例如:
double a = 123;
int v = TUtils.TryGetArrayValue<int>(new object[] { a }, 0);
答:
它与动态关键字有关。如果我将盒装的类型更改为 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},这可能是尝试强制转换为对象时的问题。如果你看一下我发布的这个版本,你会得到一种类型的对象,没有错误。
评论
这确实是奇怪的行为,而且看起来确实像是实现中的错误。我发现这种变体不会抛出异常,并且确实返回了对象: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;
}
评论
as
这是动态工作方式的问题 - 运行时活页夹在转换 时存在问题,但实际上,这确实不是问题。System.Object
我怀疑这是因为,在运行时,它本身总是.4.7 中的 C# 语言规范指出:“类型动态在运行时与对象无法区分。因此,任何用作动态的对象都只是存储为对象。dynamic
System.Object
将 的实际实例放入动态实例时,运行时绑定解析中会发生某些情况,从而导致 null 引用异常。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();
}
}
评论
我同意其他回答者的说法,他们说这看起来像一个错误。具体来说,它似乎是 C# 运行时绑定层中的一个错误,尽管我还没有彻底调查它。
对于这个错误,我深表歉意。我会将其报告给 C# 5 测试团队,我们将查看它是否已在 C# 5 中报告和修复。(它在最近的测试版中重现,因此不太可能已经报告和修复。否则,修复程序不太可能进入最终版本。在这种情况下,我们会将其视为可能的服务版本。
感谢您提请我们注意这一点。如果您想输入 Connect 问题来跟踪它,请随时这样做,并请附上指向此 StackOverflow 问题的链接。如果你不这样做,没问题;无论哪种方式,测试团队都会知道它。
评论
boxed
dynamic
dynamic