类型推断导致空引用

时间:2014-04-07 02:40:06

标签: c# ilnumerics

我正在使用ILNumerics库进行项目,但我发现用" var"有时会在计算中间改变值,例如:

// A is a matrix
var x = A[full, 0];
double xNorm = (double)norm(x);

x在第一行有效,但是导致" NullReference"执行第二行后的异常。 但如果我这样做:

// A is a matrix
ILArray<double> x = A[full, 0];
double xNorm = (double)norm(x);

计算没问题。那么这里的问题是什么?这是否意味着我们在使用&#34; var&#34;?

时需要谨慎

2 个答案:

答案 0 :(得分:2)

这不是一个错误 - 它是一个功能:)

不允许在此上下文中使用var关键字。这是three ILNumerics specific rules集合的一部分。它也可以在guickstart guide中找到。

简而言之,ILNumerics内存管理在很大程度上依赖于隐式类型转换。所有函数/属性都返回ILRetArray<T>的数组类型。这些返回类型在设计上是易变的:它们在首次使用后丢弃存储。总是。因此,可以将它们提供给其他功能或从中查询一些信息。但你宁愿不再尝试访问它!

然而,两次访问这样一个对象的唯一方法是在周围有一个引用(一个常规局部变量)。 ILNumerics指定所有局部变量必须是ILArray,ILLogical或ILCell类型。一旦将数组分配给其中一种类型的变量,隐式类型转换就会启动并将易失性返回对象“转”为更稳定且更安全的多次访问。

这就是使用ILNumerics在C#中禁止var关键字的原因。类似于Visual Basic,您还必须明确声明本地数组变量的类型。我曾经写过关于这个问题的博客文章:

http://ilnumerics.net/blog/why-the-var-keyword-is-not-allowed-in-ilnumerics/

答案 1 :(得分:1)

当用var声明时,x指的是ILRetArray'1类型的东西;如果声明为ILArray<double>,则为ILArray'1。这些是共同基础(ILDenseArray)的兄弟子类。 A的类型为ILArray<double>,其数组索引运算符返回类型ILRetArray<ElementType>

这两个类之间存在隐式转换运算符。

如果将A[full, 0]分配给类型为类型推断的变量,编译器会将其作为A的数组索引运算符的返回类型:ILRetArray<ElementType>。但是如果将x的类型显式声明为ILArray<double>,则会调用隐式转换运算符,并获得不同的实际对象。

然后将其传递给期望norm的{​​{1}},并调用另一个隐式转换运算符。并且那个有一个错误。它破坏了ILRetArray的内部状态。在致电ILInArray之前尝试此行:

norm

...它对x的影响与var d = (ILInArray<double>)x; 的调用相同。所以这就是转换。

我没有将源下载到ILNumerics以识别错误的详细信息。这可能是意味着是一个禁止操作,在这种情况下我希望他们有更好的错误报告(更新请参阅下面的@ HaymoKutschbach的答案:事实上就是这样; {{1} }是一个设计的volatile类型,只有在调用第一个隐式转换运算符之后才有效)。

向ILNumerics提交错误报告可能会很有趣,看看你听到了什么(更新:在这个帖子中有一个来自ILN的人,所以没关系)。

但回答你的问题:使用var时你需要保持谨慎;当有任何歧义的可能性时,请避免使用它。当涉及隐式转换运算符时,您需要特别谨慎。我忘记了C#中甚至存在的那些东西。我不喜欢他们。当然,错误不是由于他们使用了隐式转换运算符;这只是一个bug。但是运营商大大地和无形地混淆了代码中发生的问题。我更喜欢在源代码中显示类型转换。

感谢您发布此内容,这很有趣。