C# CA1404-尽管语句前面有return子句,CA2000-尽管没有进一步的引用用法

C# CA1404-尽管语句前面有return子句,CA2000-尽管没有进一步的引用用法,c#,code-analysis,C#,Code Analysis,我想了解为什么我的代码中会出现两个CA警告: CA2000在方法“ImpersonateValidUser(string,string,string,LogOnType,LogOnProvider,ImpersonationLevel)”中丢失作用域之前释放对象,在对象“tempWindowsIdentity”的所有引用超出作用域之前调用System.IDisposable.Dispose CA1404在p/Invoke方法“ImpersonateValidUser(string,string,

我想了解为什么我的代码中会出现两个CA警告:

CA2000在方法“ImpersonateValidUser(string,string,string,LogOnType,LogOnProvider,ImpersonationLevel)”中丢失作用域之前释放对象,在对象“tempWindowsIdentity”的所有引用超出作用域之前调用System.IDisposable.Dispose

CA1404在p/Invoke方法“ImpersonateValidUser(string,string,string,LogOnType,LogOnProvider,ImpersonationLevel)”调用GetLastWin32Error后立即调用GetLastError,但前面对“IDisposable.Dispose()”的调用不是p/Invoke语句。将调用移动到GetLastWin32Error,以便它立即跟随相关的平台调用

下面是简化的代码示例,在警告外观的位置精确注释了行:

private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    var token = IntPtr.Zero;
    var tokenDuplicate = IntPtr.Zero;
    if (NativeMethods.RevertToSelf())
    {
        if (NativeMethods.LogonUser(userName, domain, password, (int)logonType, (int)logonProvider, ref token) != 0)
        {
            if (NativeMethods.DuplicateToken(token, (int)impersonationLevel, ref tokenDuplicate) != 0)
            {
                /* CA2000 */ using (var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate))
                {
                    _impersonationContext = tempWindowsIdentity.Impersonate();
                    return;
                }
            }
        }
    }
    /* CA1404 */ var e = Marshal.GetLastWin32Error();
    throw new Win32Exception(e);
}
CA2000-在
using()
语句完成后,不会使用对象
tempWindowsIdentity
,为什么会出现此警告


CA1404-
Marshal.GetLastWin32Error()
总是在本机方法之后调用。即使在前面调用了
using()
语句的情况下,也会出现
return
子句,因此不会调用
Marshal.GetLastWin32Error()
,那么为什么会出现此警告?

此代码应该修复这些CA警告。。。不是很优雅。。。但是代码分析永远不会产生优雅的代码

private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    if (!NativeMethods.RevertToSelf())
        throw new Win32Exception(Marshal.GetLastWin32Error());

    IntPtr token = IntPtr.Zero;

    if (NativeMethods.LogonUser(userName, domain, password, (int)logonType, (int)logonProvider, ref token) == 0)
        throw new Win32Exception(Marshal.GetLastWin32Error());

    IntPtr tokenDuplicate = IntPtr.Zero;

    if (NativeMethods.DuplicateToken(token, (int)impersonationLevel, ref tokenDuplicate) == 0)
        throw new Win32Exception(Marshal.GetLastWin32Error());

WindowsIdentity tempWindowsIdentity;

    try
    {
        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
        _impersonationContext = tempWindowsIdentity.Impersonate();
    }
    finally
    {
        if (tempPort != null)
        {
            tempWindowsIdentity.Dispose();
            tempWindowsIdentity = null;
        }
    }
}
对于与CA1404有关的问题,如果您不能立即捕获错误API调用,则错误API调用引发的错误代码可能同时被来自其他托管类库方法的内部调用覆盖。
在CA2000中,方法中的WindowsIdentity已创建,但在对象的所有引用超出范围之前,对象未被释放;这样做,您就不允许在故障点引发异常。

我认为CA2000是因为您违反了规则的以下部分,这意味着您正在使用语句在
内部创建一个一次性对象

返回一次性对象需要构造该对象 在使用块外的try/finally块中


当您不调用
Marshal.GetLastWin32Error()时,也会出现CA1404在本机调用之后立即执行。尝试调用
Marshal.GetLastWin32Error()if
语句中的code>作为代码中的第一项。

我们用以下方法解决了CA1404。原因是“!=0”是LogonUser()或DuplicateToken()之后的立即调用


您好,我知道如何找到解决方法,我只是好奇我展示的方法有什么问题。您确定发布的代码会产生CA2000警告吗?这是FxCop中的一个错误,它不能正确处理范围。注意它是如何看到Dispose()调用的,但将其附加到了错误的语句中。不要让一个FxCop错误破坏你的代码,把忽略的部分翻过来。@Hans Passant:谢谢,我不知道你的知识来源是什么,但这很重要,当异常从
DuplicateToken
(或任何其他后续本机方法)抛出时会发生什么?这段代码只是将其清除。
private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    var token = IntPtr.Zero;
    var tokenDuplicate = IntPtr.Zero;
    if (NativeMethods.RevertToSelf())
    {
        var logonUserSuccessful = NativeMethods.LogonUser(userName, domain, password, (int) logonType, (int) logonProvider, ref token);
        var e = Marshal.GetLastWin32Error();  // call before comparison against 0 to avoid CA1404
        if (logonUserSuccessful != 0)
        {
            var duplicateTokenSuccessful = NativeMethods.DuplicateToken(token, (int) impersonationLevel, ref tokenDuplicate);
            e = Marshal.GetLastWin32Error();  // call before comparison against 0 to avoid CA1404
            if (duplicateTokenSuccessful != 0)
            {
                /* CA2000 */
                using (var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate))
                {
                    _impersonationContext = tempWindowsIdentity.Impersonate();
                    return;
                }
            }
        }
    }
    throw new Win32Exception(e);
}