尝试整理范围并避免可能多次调用RegisterWindowMessage 目前有一个类使用以下成员
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int RegisterWindowMessage(string lpString);
private int m_message = RegisterWindowMessage("MY_MSG");
由于我们只有一个实例,这似乎没问题,但认为使用它会更整洁。根据我的基本C#理解,这应该调用RegisterWindowMessage并将结果赋值给int并且不允许它更改。
private const int message = RegisterWindowMessage("MY_MSG");
然而,尝试这样做会导致
error CS0133: The expression being assigned to 'someclass.messageEvent' must be constant
所以现在我很困惑,这是否意味着每次m_message
被使用时都会分配和调用函数,是否还缺少其他内容?
答案 0 :(得分:7)
const
字段必须是编译时常量。如果您只想要在初始分配 1 后的执行时间内不会改变的内容,请将其设为只读:
private static readonly int Message = RegisterWindowMessage("MY_MSG");
请注意,我已将其设为静态,const
是隐式的。这意味着RegisterWindowMessage
只会为此AppDomain调用一次,这是我认为您想要的。
1 严格地说,可以在声明或静态构造函数中指定静态只读字段;可以在声明或任何实例构造函数中分配实例只读字段。它可以分配多次,通常没用,但偶尔也可以。
答案 1 :(得分:3)
这里有另一个考虑因素。 RegisterWindowMessage()可能会失败,您真的需要检查它。使用0会在出现问题时返回,否则很难诊断出来。
直接在readonly声明中将其初始化。您可以使用静态构造函数。问题是异常消息将隐藏在InnerException中。有点可以,因为失败将是罕见的。
最好的解决方案是一个懒惰地调用API的静态属性getter:
private int m_message
public static int message {
get {
if (m_message == 0) {
m_message = RegisterWindowMessage("blah");
if (m_message == 0) throw new Win32Exception();
}
return m_message;
}
}
如果可以从不同的线程调用,则使用众所周知的锁定模式。
答案 2 :(得分:1)
要添加Hans给出的答案,你可以做的不仅仅是抛出一个空的Win32Exception。这适用于使用GetLastError的任何API调用:
[DllImport("user32.dll", SetLastError = true)]
extern static int RegisterWindowMessage(string lpString);
if (m_message == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
这将产生更具信息性的例外。