У меня есть класс, который является простой оболочкой для WNetUseConnection
GC.KeepAlive сохранить контекст
Вот реализация (только для справки):
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 может вызвать финализатор до завершения этого метода. Теоретически, он должен использовать Dispose
в finally
разделе using
, но эта статья была написана умным парнем, поэтому я не уверен сейчас.
Только в случае, я предоставить код для ссылочного класса:
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 »здесь». Я мог бы даже опубликовать его в качестве ответа, я тоже очень умный парень (и скромный!), И я даже могу быть убедителен.Проблема в том, что я не знаю, в какой точке я спорю * против *, потому что вы не можете ссылаться на эту статью или говорить, почему вы считаете, что она может применяться в этом контексте. –