【问题标题】:field 'FIELD' is never assigned to, and will always have its default value字段“FIELD”从未分配给,并且始终具有其默认值
【发布时间】:2015-02-02 00:41:37
【问题描述】:
private struct TOKEN_USER
    {
        internal SID_AND_ATTRIBUTES User; //Compiler warning comes from here.
    }

[StructLayout(LayoutKind.Sequential)]
private struct SID_AND_ATTRIBUTES
   {
       internal IntPtr Sid;
       private int Attributes;
   }

将结构初始化为默认值:

TOKEN_USER tokenUser = default(TOKEN_USER);

然后进行两次必需的调用以检索指向结构的指针: (与问题无关)使用这个:

GetTokenInformation(tokenhandle, TokenInformationClass.TokenUser, sid, sidlength, ref sidlength);

然后编组回一个结构。

tokenUser = (TOKEN_USER)Marshal.PtrToStructure(sid, tokenUser.GetType());

这可行,但编译器警告我 TOKEN_USER 中的“用户”字段未分配。

R# 建议我从构造函数初始化它:

public TOKEN_USER(SID_AND_ATTRIBUTES user) : this(user)
        {
        }

但是,这不会编译,并出现错误“构造函数无法调用自身”。 我的问题是,我应该将它分配给 SID_AND_ATTRIBUTES (默认)以满足编译器的要求,还是忽略它?

测试程序:

   [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr OpenProcess(
        int dwDesiredAccess,
        [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
        int dwProcessId);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool OpenProcessToken(
        IntPtr processHandle,
        int desiredAccess,
        ref IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool GetTokenInformation(
        IntPtr tokenHandle,
        TokenInformationClass tokenInformationClass,
        IntPtr tokenInformation,
        int TokenInformationLength,
        ref int ReturnLength);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool IsValidSid(
        IntPtr SID);


    private enum TokenInformationClass
    {
        TokenUser = 1,
    }

    private const int QueryInformation = 0x400;

    private const int TokenRead = 0x20008;

    private struct TOKEN_USER
    {
        internal SID_AND_ATTRIBUTES User; //Compiler warning comes from here.
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SID_AND_ATTRIBUTES
    {
        internal IntPtr Sid;
        private int Attributes;
    }



    internal static IntPtr GetProcessHandle()
    {
        foreach (Process p in Process.GetProcesses())
        {
            using (p)
            {
                if (p.ProcessName == "explorer")
                {
                    return OpenProcess(QueryInformation, false, p.Id);
                }
            }
        }
        return IntPtr.Zero;
    }

    public void Test()
    {
        IntPtr pHandle = GetProcessHandle();

        IntPtr tokenHandle = IntPtr.Zero;
        OpenProcessToken(pHandle, TokenRead, ref tokenHandle);

        int sidlength = 0;
        GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, IntPtr.Zero, 
0, ref sidlength);

        TOKEN_USER tokenUser = default(TOKEN_USER);
        IntPtr sid = Marshal.AllocHGlobal(sidlength);

        GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser,sid, 
sidlength, ref sidlength);

        tokenUser = (TOKEN_USER)Marshal.PtrToStructure(sid, tokenUser.GetType());


        if (IsValidSid(tokenUser.User.Sid))
        {
            Debug.WriteLine("Valid!");
        }
    }

【问题讨论】:

  • 能否展示一个完整的程序
  • @DavidHeffernan 完整的程序太大而无法缩减,所以我创建了一个测试程序来演示这个问题,我使用的是进程令牌,所以我创建了一个帮助函数来返回“explorer” " 用于演示的过程令牌。
  • tokenUser = default(TOKEN_USER) 的意义何在?您稍后分配给tokenUser。编译器反对哪一行代码?
  • 是初始化为默认获取Type in tokenUser = (TOKEN_USER)Marshal.PtrToStructure(sid, tokenUser.GetType());编译器反对结构字段本身。内部 SID_AND_ATTRIBUTES 用户;
  • 不要那样做。做typeof(TOKEN_USER).

标签: c# resharper pinvoke


【解决方案1】:

只要您使用通过某种外部机制初始化的类型,例如反射或(如这里)Marshal 类,您就会看到此警告。问题是编译器无法知道该字段是如何初始化的。它所能看到的只是类型本身,类型中没有任何东西可以初始化该字段。

由于声明一个从未赋值的字段通常是编码错误,因此编译器会针对这种情况生成警告。

我不确定 R# 的确切建议是什么,但显然您不能使用与您声明的构造函数重载相同的构造函数,因为这会创建无限递归初始化。

在某些情况下,使用 : this() 初始化 struct 是有意义的(即调用默认构造函数),但这是为了处理您想要访问构造函数中的字段或属性的问题,您可以' t 直到它被初始化(调用this() 构造函数初始化整个对象)。也许这就是 R# 的“想法”?


无论如何,我在这种情况下的方法只是禁用警告,因为我确定这是误报。我初始化该字段,只是不是以编译器知道的方式。您可以使用#pragma warning 指令完成此操作。例如:

private struct TOKEN_USER
{
    #pragma warning disable 0649
    internal SID_AND_ATTRIBUTES User;
    #pragma warning restore 0649
}

请参阅Suppressing “is never used” and “is never assigned to” warnings 的回复中的相关讨论。在那里,建议您包含一条注释,解释为什么禁用警告以及为什么它是安全的;恕我直言,在您禁用警告的任何情况下,这是一个非常好的主意。

【讨论】:

  • 谢谢!我从来没有使用过#pragma ...很高兴知道。是的,R# 确实建议我发布我发布的不可编译代码的 sn-p,我正在考虑将其报告为错误...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
相关资源
最近更新 更多