调用 wininet 函数时随机出现 NullReferenceException
When calling wininet functions random NullReferenceException occur
不知道为什么,但是在调用函数时随机 InternetQueryDataAvailable
没有明显的原因发生 null ref 异常,因为它接受的参数不能为空:
[DllImport(Dlls.Wininet, SetLastError = true)]
public static extern bool InternetQueryDataAvailable([In] IntPtr hFile, [Out] out int numberOfBytesAvailable, [Optional, In] int reserved0, [Optional, In] IntPtr reserved1);
例外情况:
不,CheckHandle()
不是罪魁祸首,因为它所做的只是检查 _handle
是否为零,即无效。
此外,如果不是这样,那么在下载所有数据并尝试关闭应用程序之后,我将其设置为在应用程序关闭之前关闭所有句柄,对 InternetCloseHandle
的调用将抛出空引用即使是例外,就像 InternetQueryDataAvailable
一样,所有参数都不能为空,它只接受一个 IntPtr
:
[DllImport(Dlls.Wininet, SetLastError = true)]
public static extern bool InternetCloseHandle([In] IntPtr hInternet);
我不确定发生了什么,因为在极少数情况下一切正常,我能够下载所有数据并关闭句柄而不会抛出随机异常。
对于那些想知道带有 InternetCloseHandle 的函数是什么样子的人,它只是:
public void Dispose()
{
if (_handle != IntPtr.Zero)
{
if (!WinINet.InternetCloseHandle(_handle))
{
throw new Win32Exception();
}
_handle = IntPtr.Zero;
}
}
请注意,调用InternetQueryDataAvailable
后抛出的异常只在第一次调用后发生,所以第一次调用没问题,但之后的所有调用都有机会触发异常。
Note that the exception which is thrown after calling InternetQueryDataAvailable only occurs after the first call, so the first is fine but all the ones after have a chance of triggering the exception.
这是意料之中的事情。这是一个数据检索。那些可以 always 运行 进入外生异常。该函数是否环绕文件访问或覆盖半个地球的网络操作并不重要——这两种情况都具有外生异常的可能性。
当然具体异常还是奇数
我没有指出的是导致此空引用异常的原因是,当执行 InternetOpen
时,我立即通过 InternetSetStatusCallback
将句柄分配给状态回调通过只做 InternetSetStatusCallback(handle, CallbackMethod);
,显然发生的事情是 GC 收集了委托,因为它应该没有被使用,请注意当 InternetQueryDataAvailable
被称为状态 INTERNET_STATUS_RECEIVING_RESPONSE
和 INTERNET_STATUS_RESPONSE_RECEIVED
确实会传递给回调,所以我不确定为什么 GC 会收集委托,但这就是空引用的原因。并不是像某些人怀疑的那样 InternetQueryDataAvailable
抛出了异常。
对此的解决方案是创建一个分配给委托的字段,这样 GC 就不会收集它,因为 class 容纳它始终处于活动状态并且永远不会超出范围。
不知道为什么,但是在调用函数时随机 InternetQueryDataAvailable
没有明显的原因发生 null ref 异常,因为它接受的参数不能为空:
[DllImport(Dlls.Wininet, SetLastError = true)]
public static extern bool InternetQueryDataAvailable([In] IntPtr hFile, [Out] out int numberOfBytesAvailable, [Optional, In] int reserved0, [Optional, In] IntPtr reserved1);
例外情况:
不,CheckHandle()
不是罪魁祸首,因为它所做的只是检查 _handle
是否为零,即无效。
此外,如果不是这样,那么在下载所有数据并尝试关闭应用程序之后,我将其设置为在应用程序关闭之前关闭所有句柄,对 InternetCloseHandle
的调用将抛出空引用即使是例外,就像 InternetQueryDataAvailable
一样,所有参数都不能为空,它只接受一个 IntPtr
:
[DllImport(Dlls.Wininet, SetLastError = true)]
public static extern bool InternetCloseHandle([In] IntPtr hInternet);
我不确定发生了什么,因为在极少数情况下一切正常,我能够下载所有数据并关闭句柄而不会抛出随机异常。
对于那些想知道带有 InternetCloseHandle 的函数是什么样子的人,它只是:
public void Dispose()
{
if (_handle != IntPtr.Zero)
{
if (!WinINet.InternetCloseHandle(_handle))
{
throw new Win32Exception();
}
_handle = IntPtr.Zero;
}
}
请注意,调用InternetQueryDataAvailable
后抛出的异常只在第一次调用后发生,所以第一次调用没问题,但之后的所有调用都有机会触发异常。
Note that the exception which is thrown after calling InternetQueryDataAvailable only occurs after the first call, so the first is fine but all the ones after have a chance of triggering the exception.
这是意料之中的事情。这是一个数据检索。那些可以 always 运行 进入外生异常。该函数是否环绕文件访问或覆盖半个地球的网络操作并不重要——这两种情况都具有外生异常的可能性。
当然具体异常还是奇数
我没有指出的是导致此空引用异常的原因是,当执行 InternetOpen
时,我立即通过 InternetSetStatusCallback
将句柄分配给状态回调通过只做 InternetSetStatusCallback(handle, CallbackMethod);
,显然发生的事情是 GC 收集了委托,因为它应该没有被使用,请注意当 InternetQueryDataAvailable
被称为状态 INTERNET_STATUS_RECEIVING_RESPONSE
和 INTERNET_STATUS_RESPONSE_RECEIVED
确实会传递给回调,所以我不确定为什么 GC 会收集委托,但这就是空引用的原因。并不是像某些人怀疑的那样 InternetQueryDataAvailable
抛出了异常。
对此的解决方案是创建一个分配给委托的字段,这样 GC 就不会收集它,因为 class 容纳它始终处于活动状态并且永远不会超出范围。