GC.KeepAlive保留上下文(GC.KeepAlive to preserve a context)

编程入门 行业动态 更新时间:2024-10-28 18:22:25
GC.KeepAlive保留上下文(GC.KeepAlive to preserve a context)

我有一个类是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.

更多推荐

本文发布于:2023-07-27 17:58:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1293647.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:上下文   KeepAlive   GC   preserve   context

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!