2010-05-26 36 views
1

嘗試整理範圍並避免可能的多次調用RegisterWindowMessage。
目前有以下成員錯誤CS0133:將函數的結果分配給C#中的常量.net

[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

請參閱const和readonly之間的區別是什麼?(http://stackoverflow.com/questions/55984/what-is-the-difference-between-const-and-readonly) – heavyd 2010-05-26 20:25:56

回答

7

A const字段必須是編譯時常量。如果你只是想要的東西,不會初始分配後在執行時發生改變,使其只讀:

private static readonly int Message = RegisterWindowMessage("MY_MSG"); 

請注意,我做了這個靜態的,這是const含蓄。這意味着RegisterWindowMessage只會爲這個AppDomain調用一次,這正是我想要的。

編輯:漢斯是正確的,你應該檢查返回值。你可以在第一次使用它的時候或者初始化類型的時候這樣做 - 通常對於類型初始化器來說是拋出異常的一個好主意,但是你應該看看它的影響是什麼。


嚴格地說,一個靜態只讀字段可以在聲明或在靜態構造被分配;實例只讀字段可以在聲明中或在任何實例構造函數中分配。它可以被分配多次,這是通常沒有用,但可以只是偶爾。

+0

這是不好的, Windows API函數調用必須檢查失敗。 – 2010-05-26 21:12:11

3

這裏還有另一個考慮因素。 RegisterWindowMessage()可能會失敗,你真的需要檢查。如果出現錯誤,則使用0返回,否則將會非常難以診斷。

這敲敲直接在只讀聲明中初始化它。您可以改爲使用靜態構造函數。問題在於異常消息將被隱藏在InnerException中。有點好,也許因爲失敗將是罕見的。

最好的解決方案是一個靜態屬性的getter是懶洋洋地調用API:

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; 
    } 
} 

使用衆所周知的鎖定模式,如果這可以從不同的線程調用。

+0

感謝這個額外的指針考慮可能的錯誤情況。 – 2010-05-27 16:54:50

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()); 

這會產生更多信息異常。

+0

默認的Win32Exception構造函數已經這樣做了。 – 2010-05-27 05:17:44

+0

漢斯是對的。我不得不思考爲什麼我相信它不是這樣。 如果您未在p/invoke聲明中指定SetLastError = true,則編組器不會調用GetLastError,而Marshal.GetLastWin32Error將返回0,從而導致異常消息爲「操作成功完成」。 通過在Win32Exception構造函數中指定Marshal.GetLastWin32Error,基本上提醒自己需要將SetLastError = true添加到聲明中。 也許我是唯一一個需要這樣的提醒的人。 – Tergiver 2010-05-27 13:41:32

相關問題