2009-01-13 83 views
28

我們接管了一些.NET 1.1 Windows服務代碼,該代碼產生線程從隊列中讀取消息(請參閱eBeate eGate JMS隊列,但這並不重要),並反過來產生線程以處理目標應用程序服務中的消息。我們不斷遇到令我們困惑不已的邏輯和設計決策。這裏是一個例子,在該消息(lsMessage)已經從隊列中檢索並準備處理對象構造函數可以返回null嗎?

if(lsMessage != null) 
{ 
    // Initialize a new thread class instance, pass in message 
    WorkerThread worker = new WorkerThread(lsMessage); 

Process: 
    // Start a new thread to process the message 
    Thread targetWorker = new Thread(new ThreadStart(worker.ProcessMessage)); 
    if(targetWorker != null) 
    { 
     targetWorker.Priority = ThreadPriority.Highest; 
     targetWorker.Name = "Worker " + queueKey.ToString(); 
     targetWorker.Start(); 

     // wait for worker thread to join back in specified period 
     bool isFinished = targetWorker.Join(SYNC_THREAD_TIMEOUT); 

     string message = worker.replyMsg; 

     if (!isFinished) // BF is timeout 
     { 
      targetWorker.Abort(); 

      // [obscure developer name] 25/10/2004: calling Join() to wait for thread to terminate. 
      // for EAI listener threads problem, ensure no new thread is started 
      // before the old one ends 
      targetWorker.Join(); 

      // prepare reply message 
      string errorMsg = string.Format("EAIMsg {0}: BF is timeout. Send sync message back to caller.", worker.messageKey); 
      log.Debug(errorMsg); 

      message = worker.GenErrorCode(message, errorMsg); 
     } 

     // Commit message 
     MQ.ReceiverCommit(queueKey, worker.messageKey, false); 

     // Send back the response to the caller 
     MQ.RespondSend(queueKey, message); 
    } 
    else 
    { 
     log.Debug(string.Format("Fail to start worker thread to process sync message. Thread returned is null. Sleep for {0} milliseconds.", LIMIT_RESOURCE_SLEEP)); 
     Thread.Sleep(LIMIT_RESOURCE_SLEEP); 
     goto Process; 
    } 
} 

請忽略使用標籤和GOTO暫時的;這不是問題。我們的困惑是在實例化後檢查線程對象是否爲空。下面的else語句似乎表明之前的開發人員遇到過這種情況。當然,原來的開發者早已不在了。所以我們想知道,CLR是否可以在調用構造函數之後實例化一個對象並返回null?我們不瞭解這種可能性。

+0

長得重構或代碼的改變對我的結果。也許構造線是其他的東西,比如`GetThread()`。 – usr 2016-12-12 23:11:36

回答

29

在我看來,else聲明暗示的是之前的開發人員不知道他們的C#。構造函數總是返回一個構造對象或拋出異常。

在很古老的時代,C++構造函數可能返回null,所以也許問題來自於此。這在C++中不再是這樣,至少對於默認的new運算符。

25

編輯:澄清存在瘋狂的邊緣情況在那裏你可以從一個類構造函數得到null,但坦率地說,我不認爲任何真正的代碼應該曾經期望應對這種級別的瘋狂:What's the strangest corner case you've seen in C# or .NET? 。全部正常意圖:它不會發生。


不,你不能從一個構造得到空(Thread是一類)。我知道在哪裏構造可以(似乎)返回null的唯一情況是Nullable<T> - 即

object foo = new int?(); // this is null 

這是一個稍微大一點的問題,仿製藥:

static void Oops<T>() where T : new() { 
    T t = new T(); 
    if (t == null) throw new InvalidOperationException(); 
} 

static void Main() { 
    Oops<int?>(); 
} 

(當然,也有辦法檢查/處理該場景,如: class

除此之外,構造函數將始終返回一個對象(或初始化一個結構體)或拋出異常。

+0

當然,我們在這裏並不使用空值; .NET 1.1 – icelava 2009-01-13 08:38:22

+2

的不錯 - 但我認爲這是值得一提的是邊緣情況;-p – 2009-01-13 08:40:25

+0

而且這幾乎是* *總是到新創建的對象的引用,太。我所知道的唯一例外是一個字符串的情況。 – 2009-01-13 08:45:30

2

不!該空檢查是多餘的。很多移到C#的C++開發者都有這種空檢查的習慣,我猜這在這裏是一樣的。

唯一的是你應該檢查文檔,看看構造函數是否可以拋出任何異常。在你的情況下,請參閱http://msdn.microsoft.com/en-us/library/xx3ezzs2.aspx,如前所述,構造函數將始終返回有效的obj。

0

由於core提到,運算符重載可能會使得看起來構造函數返回null,這並不是真正發生的情況。文章core的作者發現,他們沒有看到它的使用,但它實際上用於非常流行的產品:Unity。

這將編譯和運行時日誌消息:

using UnityEngine; 

public class Test:MonoBehaviour 
{ 
    void Start() 
    { 
     AudioSource as = new AudioSource(); 

     if (as == null) 
     { 
      Debug.Log("Looks null to me."); 
     } 
    } 
} 

現在,這裏是我的錯,因爲一個應該呼叫AudioSource直接構造。但一個應該知道==運營商在繼承樹的根團結可以參考的對象超載。以下是關於UnityEngine.ObjectUnityEngine.Object==的運算符:

與空比較時要小心。

例如

GameObject go = new GameObject(); 
Debug.Log (go == null); // false 

Object obj = new Object(); 
Debug.Log (obj == null); // true 

Instatiating一個遊戲物體將其添加到現場,所以它完全 初始化(!破壞)。實例化一個簡單的UnityEngine.Object 有沒有這樣的語義,所以(原文)它停留在 比較真實爲null「破壞」的狀態。

雖然實例化一個GameObject初始化,實例化對象AudioSource沒有,所以用null返回true比較。

這種不尋常的成語是憑藉試圖引用未初始化AudioSource對象的屬性將引發空引用異常,這是我最初誤解爲是指對象引用的事實更加隱蔽取得了null,而不是財產。

其他人已經回答了OP的問題,但我想添加這個答案,因爲OP的代碼實際上可能使有道理的,如果Thread類其中是不是我們希望它是一個,就像Object(及其後代)是不太可能,你希望它是一個統一的腳本是什麼(也就是,它實際上是UnityEngine.Object,而不是System.Object,它可以讓你重載==運營商,這麼糊塗了)。

相關問題