2012-01-23 51 views
2

嗨我不確定一個通用的方法是解決我的問題的正確方法。我需要解析一個XML文件並從中讀取項目。項目可以是orderline,notes,attachments等。獲得這些項目的基本步驟都是一樣的。我如何創建1個方法來創建這些項目的列表並調用特定的方法來讀取項目?我可以使用泛型方法作爲一種模板模式嗎?

public override IList<T> GetItems<T>(XPathNavigator currentOrder) where T : ISortableByLineNumber, new() 
    { 
     var itemList = new List<T>(); 
     var itemXmlNodes = currentOrder.Select(OrderXPath); 
     if (itemXmlNodes == null) 
      throw new Exception(""); 
     var lineNumber = 1; 
     foreach (XPathNavigator itemXmlNode in itemXmlNodes) 
     { 
      var item = new T(); 
      item = ReadItem(itemXmlNode, lineNumber++, item); 
      itemList.Add(item); 
      Logger.Debug(string.Format("Added item {0}", item)); 
     } 
     return itemList; 
    } 

我想我可以用ReadItem方法做到這一點。我會爲我將要閱讀的每種類型的項目創建重載。

private ISortableByLineNumber ReadItem(XPathNavigator itemXmlNode, int i, OrderLine item) 
    { 
     // specific code to read a orderLine 
    } 

    private ISortableByLineNumber ReadItem(XPathNavigator itemXmlNode, int i, Note item) 
    { 
     // specific code to read a note 
    } 

但是,當我嘗試編譯這個我能得到「的最佳重載方法匹配‘XmlOrderParser.XmlOrders.Prs3XmlFileWithOrders.ReadItem(System.Xml.XPath.XPathNavigator類,INT,XmlOrderParser.Entities.OrderLine)’有一些無效的論點「。問題是編譯器不知道如何將T轉換爲OrderLine或Note。

dynamic item = new T(); // instead of var item = new T(); 

因爲item現在是dynamic運行並根據實際類型自動重載解析:

+0

請問您的類:訂單行,Note和其他的實現接口ISortableByLineNumber? – VS1

+0

是的,他們都實現了該接口。我還沒有調用函數,所以這是一個編譯時錯誤,而不是運行時錯誤。 –

+0

那麼我想你應該使用接口類型而不是你的方法參數中的具體類型,我已經爲此發佈了一個答案.. – VS1

回答

2

如果您使用的是.NET 4,你可以通過改變只有一兩件事,利用新dynamic類型項目。
請注意,如果T是不存在過載的類型,您將收到運行時異常。


下面的代碼演示您的問題(粘貼到LINQPad並選擇「C#程序」作爲語言):

void Main() 
{ 
    Method<Class1>(); // Outputs Class1 
    Method<Class2>(); // Outputs Class2 
    Method<Class2b>(); // Outputs Class2, because it falls back to the base type 
    Method<Class3>(); // Throws exception 
} 

void Method<T>() where T : new() 
{ 
    dynamic c = new T(); 
    Method(c); 
} 

void Method(Class1 c) { Console.WriteLine("Class1"); } 
void Method(Class2 c) { Console.WriteLine("Class2"); } 

class Class1 {} 
class Class2 {} 
class Class2b : Class2 {} 
class Class3 {} 
+1

偉大的,似乎解決了問題! –

+0

@munnik:太好了!不要忘記接受我的回答:[如何接受答案](http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work)。 –

+0

+1,儘管我會添加更多關於爲什麼需要將它推遲到運行時的信息,即編譯器不知道'GetItems '中的'T'是否是'OrderLine'或'Note'等中的任何一個因爲沒有通用的限制條件。 – Krizz

0

這是因爲在編譯的時候你不知道你要的方法需要。爲了解決這個問題,你需要找到正確的方法並調用它。嘗試像這樣:

MethodInfo mi = typeof(YourClass).GetMethod("ReadItem", 
    BindingFlags.NonPublic, 
    null, 
    new Type[] { typeof(XPathNavigator), typeof(int), typeof(T) }, 
    null); 
item = mi.Invoke(this, new object { itemXmlNode, lineNumber++, item }); 

希望它有幫助。祝你好運!

+1

這或多或少是「動態」所做的手動轉錄。如果使用C#<4.0,那麼可以很好地替代Daniel的答案,但如果T是一些重載的參數類型的子類,或者我錯了,可能會出現問題? – Krizz

0

正如你在評論說,您的所有課程訂單行,注意等實現ISortableByLineNumber接口,這樣你就可以改變你的方法ReadItem來定義:

private OrderLine ReadItem(XPathNavigator itemXmlNode, int i, ISortableByLineNumber item) 
{ 

} 

並傳遞給實際類型所述item PARAM在上述方法將具有其在運行時執行的特定實施方式中,因此,如果是item類型OrderLineGetItems<T>方法則其具體實施將被調用傳遞時等..

釷上述E的方法定義的改變會使你的方法定義特定接口,而不是具體類型具體是interface based編程實踐中的一個鏈接如下解釋:

http://visualstudiomagazine.com/articles/2010/01/01/interface-based-programming.aspx

What exactly is "interface based programming"?

相關問題