我有一个类是WNetUseConnection的简单包装器
这是一个实现(仅供参考):
internal class RemoteFileSystemContext : IDisposable { private readonly string _remoteUnc; private bool _isConnected; public RemoteFileSystemContext(string remoteUnc, string username, string password, bool promptUser) { if (WindowsNetworking.TryConnectToRemote(remoteUnc, username, password, promptUser)) { _isConnected = true; _remoteUnc = remoteUnc; } else { GC.SuppressFinalize(this); } } public void Dispose() { Dispose(true); } ~RemoteFileSystemContext() { Dispose(false); } private void Dispose(bool isDisposing) { if (!_isConnected) return; _isConnected = false; if (isDisposing) { GC.SuppressFinalize(this); } WindowsNetworking.DisconnectRemote(_remoteUnc); } }这是用法:
using (var context = WindowsNetworking.CreateRemoteContext(storagePath, login, pass)) { // do something with storagePath GC.KeepAlive(context); }问题是我是否应该写GC.KeepAlive(context) ? 我的意思是我没有写这样的代码,直到我读了一篇文章(关于AsyncLock ,但现在我找不到链接),现在我不确定GC是否可以在此方法完成之前调用终结器。 理论上,它应该在finally using部分使用Dispose ,但是这篇文章是由聪明人写的,所以我现在不确定。
为了以防万一,我提供了引用类的代码:
public static class WindowsNetworking { public static bool TryConnectToRemote(string remoteUnc, string username, string password, bool promptUser = false) { bool isUnc = remoteUnc != null && remoteUnc.Length >= 2 && remoteUnc[0] == '\\' && remoteUnc[1] == '\\'; if (!isUnc) { return false; } ConnectToRemote(remoteUnc, username, password, promptUser); return true; } public static IDisposable CreateRemoteContext(string remoteUnc, string username, string password, bool promptUser = false) { return new RemoteFileSystemContext(remoteUnc, username, password, promptUser); } public static void DisconnectRemote(string remoteUNC) { var ret = (NetworkError) WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false); if (ret != NetworkError.NO_ERROR) { throw new Win32Exception((int) ret, ret.ToString()); } } [DllImport("Mpr.dll")] private static extern int WNetUseConnection( IntPtr hwndOwner, NETRESOURCE lpNetResource, string lpPassword, string lpUserID, int dwFlags, string lpAccessName, string lpBufferSize, string lpResult ); [DllImport("Mpr.dll")] private static extern int WNetCancelConnection2( string lpName, int dwFlags, bool fForce ); [StructLayout(LayoutKind.Sequential)] private class NETRESOURCE { public int dwScope = 0; public int dwType = 0; public int dwDisplayType = 0; public int dwUsage = 0; public string lpLocalName = ""; public string lpRemoteName = ""; public string lpComment = ""; public string lpProvider = ""; } private static void ConnectToRemote(string remoteUNC, string username, string password, bool promptUser) { NETRESOURCE nr = new NETRESOURCE { dwType = RESOURCETYPE_DISK, lpRemoteName = remoteUNC }; NetworkError ret; if (promptUser) ret = (NetworkError) WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null); else ret = (NetworkError) WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null); if (ret != NetworkError.NO_ERROR) { throw new Win32Exception((int) ret, ret.ToString()); } } }I have a class which is is a simple wrapper for WNetUseConnection
Here is an implementation (just for reference):
internal class RemoteFileSystemContext : IDisposable { private readonly string _remoteUnc; private bool _isConnected; public RemoteFileSystemContext(string remoteUnc, string username, string password, bool promptUser) { if (WindowsNetworking.TryConnectToRemote(remoteUnc, username, password, promptUser)) { _isConnected = true; _remoteUnc = remoteUnc; } else { GC.SuppressFinalize(this); } } public void Dispose() { Dispose(true); } ~RemoteFileSystemContext() { Dispose(false); } private void Dispose(bool isDisposing) { if (!_isConnected) return; _isConnected = false; if (isDisposing) { GC.SuppressFinalize(this); } WindowsNetworking.DisconnectRemote(_remoteUnc); } }and here is usage:
using (var context = WindowsNetworking.CreateRemoteContext(storagePath, login, pass)) { // do something with storagePath GC.KeepAlive(context); }The question is if I should write GC.KeepAlive(context) or not? I mean I didn't write code like this until I read an article (about AsyncLock, but now I can't find a link), and now I'm not sure if GC can call a finalizer before this method finishes. Theoretically, it should use Dispose in finally section of using, but this article was written by a smart guy, so I'm not sure now.
Just in case, I provide code for referenced class:
public static class WindowsNetworking { public static bool TryConnectToRemote(string remoteUnc, string username, string password, bool promptUser = false) { bool isUnc = remoteUnc != null && remoteUnc.Length >= 2 && remoteUnc[0] == '\\' && remoteUnc[1] == '\\'; if (!isUnc) { return false; } ConnectToRemote(remoteUnc, username, password, promptUser); return true; } public static IDisposable CreateRemoteContext(string remoteUnc, string username, string password, bool promptUser = false) { return new RemoteFileSystemContext(remoteUnc, username, password, promptUser); } public static void DisconnectRemote(string remoteUNC) { var ret = (NetworkError) WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false); if (ret != NetworkError.NO_ERROR) { throw new Win32Exception((int) ret, ret.ToString()); } } [DllImport("Mpr.dll")] private static extern int WNetUseConnection( IntPtr hwndOwner, NETRESOURCE lpNetResource, string lpPassword, string lpUserID, int dwFlags, string lpAccessName, string lpBufferSize, string lpResult ); [DllImport("Mpr.dll")] private static extern int WNetCancelConnection2( string lpName, int dwFlags, bool fForce ); [StructLayout(LayoutKind.Sequential)] private class NETRESOURCE { public int dwScope = 0; public int dwType = 0; public int dwDisplayType = 0; public int dwUsage = 0; public string lpLocalName = ""; public string lpRemoteName = ""; public string lpComment = ""; public string lpProvider = ""; } private static void ConnectToRemote(string remoteUNC, string username, string password, bool promptUser) { NETRESOURCE nr = new NETRESOURCE { dwType = RESOURCETYPE_DISK, lpRemoteName = remoteUNC }; NetworkError ret; if (promptUser) ret = (NetworkError) WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null); else ret = (NetworkError) WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null); if (ret != NetworkError.NO_ERROR) { throw new Win32Exception((int) ret, ret.ToString()); } } }最满意答案
GC.KeepAlive方法为空 。 它所做的只是确保从代码中的该点读取特定变量,因为否则该变量永远不会再次读取,因此不是保持对象存活的有效引用。
这里没有意义,因为您传递给KeepAlive的相同变量会在稍后的时间点再次读取 - 在调用Dispose时隐藏的finally块期间。 所以, GC.KeepAlive在这里什么也没做。
The GC.KeepAlive method is empty. All it does is ensure that a particular variable is read from at that point in the code, because otherwise that variable is never read from again and is thus not a valid reference to keep an object alive.
It's pointless here because the same variable that you're passing to KeepAlive is read from again at a later point in time - during the hidden finally block when Dispose is called. So, the GC.KeepAlive achieves nothing here.
更多推荐
发布评论