在"using语句"中将代码作为参数传递给函数

6
这段代码在我这里可以正常工作:
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    [DllImport("kernel32.dll")]
    public static extern bool CloseHandle(IntPtr token);

enum LogonType
    {
        Interactive = 2,
        Network = 3,
        Batch = 4,
        Service = 5,
        Unlock = 7,
        NetworkClearText = 8,
        NewCredentials = 9
    }
    enum LogonProvider
    {
        Default = 0,
        WinNT35 = 1,
        WinNT40 = 2,
        WinNT50 = 3
    }

private void Button1_Click()
    { 
        IntPtr token = IntPtr.Zero;
        LogonUser("Administrator",
                  "192.168.1.244",
                  "PassWord",
                  (int)LogonType.NewCredentials,
                  (int)LogonProvider.WinNT50,
                  ref token);
        using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(token))
        {
    CloseHandle(token);
    /*
    Code_of_Do_Something
    */
    }
}

但是...这意味着每次需要模拟(在远程机器=服务器上执行某些操作)时,我都必须重复"Button1_Click()"中的最后一段代码。 所以我的问题是:是否可能像这个示例一样做到这一点? enter image description here

1
使用委托?http://msdn.microsoft.com/zh-cn/library/aa288459(v=vs.71).aspx - Unix von Bash
您也可以返回上下文值(WindowsIdentity.Impersonate)并自行处理其处置。 - RvdK
1
CloseHandle 应该放在代码之后,不是吗?实际上,它应该在自己的 finally 块中,以便始终执行。 - Konrad Rudolph
同意。您有什么证据可以称呼CloseHandle在那里?如果WindowsIdentity.Impersonate()失败,那么您根本不会调用它。 - David Heffernan
2个回答

3
您可以使用委托来实现此目的。最简单的方法是使用 ActionFunc。如果不需要返回值,请使用 Action:
private void RunImpersonated(Action act)
{
    IntPtr token = IntPtr.Zero;
    LogonUser("Administrator",
              "192.168.1.244",
              "PassWord",
              (int)LogonType.NewCredentials,
              (int)LogonProvider.WinNT50,
              ref token);
    try
    {
        using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(token))
        {
            // Call action
            act();
        }
    }
    finally
    {
        CloseHandle(token);
    }
}

请注意,有许多带有泛型类型参数的变化可以让您以强类型的方式为 ActionFunc 委托提供参数。例如,如果您需要一个整数参数,请使用 Action<int> 而不是仅使用 Action

还要注意我创建了一个 finally 块,无论发生异常与否都会关闭句柄。

为了调用该函数,可以使用 lambda 表达式:

private void button1_Click(object sender, EventArgs e)
{
    RunImpersonated(() => {
        DirectoryInfo dir = new DirectoryInfo( @"\\192.168.1.244\repository");
        foreach (DirectoryInfo di in dir.GetDirectories()) 
        { 
            lable_folders_count.Text = Convert.ToString(dir.GetFileSystemInfos().Length); 
        }
    });
}

请问如何将这段代码放入一个Action中?code DirectoryInfo dir = new DirectoryInfo(@"\192.168.1.244\repository); foreach (DirectoryInfo di in dir.GetDirectories()) { lable_folders_count.Text = Convert.ToString(dir.GetFileSystemInfos().Length); } code - CrownFord
@CrownFord:我更新了帖子并包含了一个示例。希望它有所帮助。 - Markus
我得到了这个错误:"方法必须有返回类型" 关于:RunImpersonated(() - CrownFord
@CrownFord:错误显示在哪里?在 public void RunImpersonated(Action act) 还是在你调用 RunImpersonated 的地方? - Markus
请查看此处的屏幕截图:[链接](http://www.fa6er.com/ad/error.png) - CrownFord
@CrownFord:你需要从另一个方法中调用RunImpersonated,例如在button1的事件处理程序中。我已经更新了示例。 - Markus

1

是的,可以将代码作为参数传递。但让我们在不使用lambda的情况下解决您的问题:

private void Button1_Click()
{
    using(GetImpersonationContext())
    {
        /* code here */
    } 
}
private WindowsImpersonationContext GetImpersonationContext()
{
    IntPtr token = IntPtr.Zero;
    LogonUser("Administrator",
              "192.168.1.244",
              "PassWord",
              (int)LogonType.NewCredentials,
              (int)LogonProvider.WinNT50,
              ref token);

    WindowsImpersonationContext context = WindowsIdentity.Impersonate(token);
    CloseHandle(token);
    return context;
}

它运行得很好,谢谢...只需要从WindowsIdentity.Impersonate(token);中移除最后一个分号)); - CrownFord

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接