字段 'FIELD' 从未分配给,并且始终具有其默认值
field 'FIELD' is never assigned to, and will always have its default value
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 中的 'User' 字段未分配。
R# 建议我从构造函数初始化它:
public TOKEN_USER(SID_AND_ATTRIBUTES user) : this(user)
{
}
但是,这无法编译,出现错误 "Constructor cannot call itself"。
我的问题是,我应该将它分配给 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!");
}
}
只要您使用通过某种外部机制初始化的类型,例如反射或(如此处)Marshal
class,您就会看到此警告。问题是编译器无法知道该字段是如何初始化的;它所能看到的只是类型本身,类型中没有任何东西可以初始化该字段。
由于声明一个从未赋值的字段通常是编码错误,因此编译器会针对这种情况生成警告。
我不确定 R# 的确切建议是什么,但显然您不能使用与您声明的相同的构造函数重载,因为那样会创建无限递归初始化。
在某些情况下,使用 : this()
初始化 struct
是有意义的(即调用默认构造函数),但这是为了处理您想要访问字段或 属性 在构造函数中,你不能直到它被初始化(调用 this()
构造函数初始化整个对象)。也许这就是 R# 的 "thinking"?
无论如何,我在这种情况下的方法只是禁用警告,因为我确信这是误报。我 do 初始化字段,只是不是以编译器知道的方式。您可以使用 #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 的回答中的相关讨论。在那里,建议您添加一条注释,解释为什么警告被禁用以及为什么它是安全的;恕我直言,在禁用警告的任何情况下,这是一个非常好的主意。
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 中的 'User' 字段未分配。
R# 建议我从构造函数初始化它:
public TOKEN_USER(SID_AND_ATTRIBUTES user) : this(user)
{
}
但是,这无法编译,出现错误 "Constructor cannot call itself"。 我的问题是,我应该将它分配给 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!");
}
}
只要您使用通过某种外部机制初始化的类型,例如反射或(如此处)Marshal
class,您就会看到此警告。问题是编译器无法知道该字段是如何初始化的;它所能看到的只是类型本身,类型中没有任何东西可以初始化该字段。
由于声明一个从未赋值的字段通常是编码错误,因此编译器会针对这种情况生成警告。
我不确定 R# 的确切建议是什么,但显然您不能使用与您声明的相同的构造函数重载,因为那样会创建无限递归初始化。
在某些情况下,使用 : this()
初始化 struct
是有意义的(即调用默认构造函数),但这是为了处理您想要访问字段或 属性 在构造函数中,你不能直到它被初始化(调用 this()
构造函数初始化整个对象)。也许这就是 R# 的 "thinking"?
无论如何,我在这种情况下的方法只是禁用警告,因为我确信这是误报。我 do 初始化字段,只是不是以编译器知道的方式。您可以使用 #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 的回答中的相关讨论。在那里,建议您添加一条注释,解释为什么警告被禁用以及为什么它是安全的;恕我直言,在禁用警告的任何情况下,这是一个非常好的主意。