我有以下功能:
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);
答案 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},这可能是试图转换为对象时的问题。如果你看一下我发布的这个版本,就会得到一种对象而且没有错误。