2013-07-18 50 views
0

所以我有許多不同的潛在對象可以輸出數據(字符串)。我想要做的就是運行一個通用的Output.WriteLine函數,並用可能的參數來定義輸出到哪裏。我有什麼碼 -C#如何判斷一個對象是否實現了一個特定的方法

//Defined in static class Const 
public enum Out : int { Debug = 0x01, Main = 0x02, Code = 0x04 }; 

static class Output 
{ 
    private static List<object> RetrieveOutputMechanisms(Const.Out output) 
    { 
     List<object> result = new List<object>(); 

    #if DEBUG 
     if (bitmask(output, Const.Out.Debug)) 
      result.Add(1);//Console); //I want to add Console here, but its static 
    #endif 
     if (bitmask(output, Const.Out.Main)) 
      if (Program.mainForm != null) 
       result.Add(Program.mainForm.Box); 

     if (bitmask(output, Const.Out.Code)) 
      if (Program.code!= null) 
       result.Add(Program.code.Box); 

     return result; 
    } 

    public static void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main) 
    { 
     Console.WriteLine(
     List<object> writers = RetrieveOutputMechanisms(output); 
     foreach (object writer in writers) 
      writer.WriteLine(str, color); 
    } 
} 

一點來看,是輸出目的地並不總是存在的,因爲它們是在可能時,這些調用被稱爲或可能不存在的形式。因此,想法是確定要嘗試打印哪些內容,確定它是否存在,將其添加到要打印的內容的列表中,然後循環並打印到所有內容,如果它們實現「WriteLine」方法。

,我已經遇到這兩個問題,是

  1. 該控制檯是一個靜態類,而不能正常(據我所知雲)被添加到對象列表。
  2. 我不知道我該如何斷言列表中的對象定義了WriteLine,並將它們轉換爲適用於多個基類型的東西。假設我可以讓控制檯在這個方案中正常工作,這將是一個明顯的問題,它不是與實際的Boxes相同的基本類型,但是,如果我的東西不是Box,那麼這將是可愛的做像

    的foreach(在作家的對象作家) .WriteLine(STR,顏色)

,這樣我就不必單獨投他們。

我不簡單WriteLine從RetrieveOutputMechanisms函數,更大的原因是我希望這不僅覆蓋WriteLine,這意味着我需要將位掩碼代碼複製到每個函數。

編輯:我意識到,將程序添加到公共屬性是一個壞主意,如果你知道如何避免它(必要性來自需要能夠訪問任何WriteLine能夠形式對象來去,從任何地方),請一定要詳細說明。

回答

1

一種方法是使用Action(代表)並將其存儲在List中。這將適用於Console和任何其他類,因爲您可以輕鬆編寫lambda(或2.0委託)將輸出變量映射到調用方法中的正確參數。將不需要鑄造。它可以工作是這樣的:

(這裏假設你正在使用C#3.5或更高版本,但你可以做到這一切什麼都從2.0和使用委託)

static class Output 
{ 
    private static List<Action<string, Color>> RetrieveOutputMechanisms(Const.Out output) 
    { 
     List<Action<string, Color>> result = new List<string, Color>(); 

    #if DEBUG 
     if (bitmask(output, Const.Out.Debug)) 
      result.Add((s, c) => Console.WriteLine(s, c)); //I want to add Console here, but its static 
    #endif 
     if (bitmask(output, Const.Out.Main)) 
      if (Program.mainForm != null) 
       result.Add((s, c) => Program.mainForm.Box.WriteLine(s, c)); 

     if (bitmask(output, Const.Out.Code)) 
      if (Program.code!= null) 
       result.Add((s, c) => Program.code.Box.WriteLine(s, c)); 

     return result; 
    } 

    public static void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main) 
    { 
     var writers = RetrieveOutputMechanisms(output); 
     foreach (var writer in writers) 
      writer(str, color); 
    } 
} 

(編輯加)

您可以更改這一點,以允許類「註冊」,以便能夠爲Output類本身的特定「輸出機制」進行書寫。你可以讓Output成爲一個單身人士(有些人反對這樣做,但是爲了達到這個目的,它會比在你的主程序中粘貼公共靜態變量更好)。下面是更多的顯著改變你原來的類的例子:

public sealed class Output 
{ 
    private Dictionary<Out, Action<string, Color>> registeredWriters = new Dictionary<Out, Action<string, Color>>(); 

    public static readonly Output Instance = new Output(); 

    private void Output() { } // Empty private constructor so another instance cannot be created. 

    public void Unregister(Out outType) 
    { 
     if (registeredWriters.ContainsKey(outType)) 
      registeredWriters.Remove(outType); 
    } 

    // Assumes caller will not combine the flags for outType here 
    public void Register(Out outType, Action<string, Color> writer) 
    { 
     if (writer == null) 
      throw new ArgumentNullException("writer"); 

     if (registeredWriters.ContainsKey(outType)) 
     { 
      // You could throw an exception, such as InvalidOperationException if you don't want to 
      // allow a different writer assigned once one has already been. 
      registeredWriters[outType] = writer; 
     } 
     else 
     { 
      registeredWriters.Add(outType, writer); 
     } 
    } 

    public void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main) 
    { 
     bool includeDebug = false; 
     #if DEBUG 
     includeDebug = true; 
     #endif 

     foreach (var outType in registeredWriters.Keys) 
     { 
      if (outType == Const.Out.Debug && !includeDebug) 
       continue; 

      if (bitmask(output, outType)) 
       registeredWriters[outType](str, color); 
     } 
    } 
} 

然後在其他地方在你的程序,比如在窗體類,註冊一個作家,這樣做:

Output.Instance.Register(Const.Out.Main, (s, c) => this.Box.WriteLine(s, c)); 

當你的表格你可以這樣做:

Output.Instance.Unregister(Const.Out.Main); 

然後另一種方法是不使用單身。然後,您可以爲不同的目的使用多個Output實例,然後將這些實例注入到其他類中。例如,將主表單的構造函數更改爲接受Output參數,並將其存儲爲對象變量以供以後使用。然後主窗體可以將其傳遞給也需要它的子窗體。

+0

這看起來正是我想要的。一旦我測試,這將是答案。你知道一種方式,我可以在輸出類中「註冊」每個對象,因爲它們是被破壞的,並且註銷它們?現在他們是公開的,並且被認爲是程序的公共財產,對我來說這似乎非常黑客。 – DanielCardin

+0

出於好奇,我爲什麼不能繼續使用靜態類?我想知道,因爲我對Singletons知之甚少,而且我只是編輯了你的代碼而不使用它們,至少編譯它。 – DanielCardin

+0

它*看起來*工作得很好! (至少作爲一個靜態類,我沒有把所有的輸出替換成輸出。實例的) – DanielCardin

0

如果你的對象有需要寫這樣的表現數據:

一個始終寫入控制檯並登錄 乙始終寫入日誌 C時,同時寫入到控制檯

對於所有的數據,那麼你最好的選擇就是聲明一個接口並讓它們每個都實現輸出的接口方法。然後,在你的調用代碼中,聲明它們不是它們的實際類型,而不是類型IOutput或者你調用的具有該方法的任何接口。然後有兩個輔助方法,一個用於實際輸出到控制檯,另一個用於實際輸出到日誌文件。 A會呼叫助手,B和C各自的助手。

如果,另一方面,你的對象將寫入各種日誌在不同時間:

A,B和C,有時寫的安慰,有時登錄,這取決於某些屬性

然後我會建議你創建一個事件處理程序,以便當某個類想要寫入內容時。然後,讓邏輯來辨別寫入控制檯的內容以及寫入什麼來登錄監聽器類並將相應的內容附加到該輸出事件。通過這種方式,您可以將關於正在寫入什麼內容的邏輯保留在封裝了該功能的類中,同時讓A,B和C類免於可能會讓您隨心所欲的依賴關係。如你所描述的那樣,考慮使用單片方法,它使用了位掩碼。只要A,B或C的記錄行爲發生變化,或者需要添加新的輸出,您就需要擔心一個類或方法會同時影響所有這些類。這使得它不易維護,並且更難以測試錯誤。

+0

我的方法的主要負面部分是我需要將公共變量添加到程序爲了做到這一點,雖然在此之後,添加一個新的輸出不會改變其他任何東西。編寫一個監聽器類並不能幫助我,因爲我的問題與確定是否實現了WriteLine(以及如何讓控制檯符合此)有關,這仍然是一個問題。 – DanielCardin

0
MethodInfo methodname = typeof(object).GetMethod("MethodA"); 

然後,只需使用if語句來檢查methodname是否爲null。

+0

我不確定那對我有什麼影響。除非我錯過了某些東西,否則我仍然需要單獨將每個東西都投射到它的類型上,這會破壞目標 – DanielCardin

相關問題