我正在使用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;?
时需要谨慎答案 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。但是运营商大大地和无形地混淆了代码中发生的问题。我更喜欢在源代码中显示类型转换。
感谢您发布此内容,这很有趣。