2016-10-26 26 views
0

我有多個方法,其選自具有下列格式的XML讀取數據:如何使返回不同類型的方法通用,但接受相同類型的實例?

<?xml version = "1.0" encoding="UTF-8" standalone="yes"?> 
<document> 
    <employee> 
     <name> 
      <lastname>Sample</lastname> 
      <firstname>Test</firstname> 
     </name> 
     <professionalDetails> 
      <hiredate>October 15, 2016</hiredate> 
      <designation>Clerk</designation> 
     </professionalDetails> 
     <projects> 
      <project> 
       <product>Printer</product> 
       <id>111</id> 
       <price>$111.00</price> 
      </project> 
      <project> 
       <product>Laptop</product> 
       <id>222</id> 
       <price>$989.00</price> 
      </project> 
     </projects> 
    </employee> 
</document> 

爲了讀取上述數據,我有與它們各自的類中的以下方法。

  • 請注意,我有我自己的實現「GetElementAsString」的方法。忍受我不提供這個的實施。

方法:

private static NameDetails GetsNameDetails(XNode content) 
    { 
     var element = content.XPathSelectElement("document/employee/name"); 

     return new NameDetails 
     { 
      FirstName = element.GetElementAsString("firstName"), 
      LastName = element.GetElementAsString("lastName") 
     }; 
    } 

    private static ProfessionalDetails GetsProfessionalDetailsDetails(XNode content) 
    { 
     var element = content.XPathSelectElement("document/employee/professionalDetails"); 

     return new ProfessionalDetails 
     { 
      HireDate = element.GetElementAsString("hiredate"), 
      Designation = element.GetElementAsString("designation") 
     }; 
    } 

    private static Projects GetsProjectDetails(XNode content) 
    { 
     var element = content.XPathSelectElement("document/employee/projects/project"); 

     return new Projects 
     { 
      Id = element.GetElementAsString("id"), 
      Price = element.GetElementAsString("price"), 
      Product = element.GetElementAsString("product") 
     }; 
    } 
} 

internal class Projects 
{ 
    public int Id { get; set; } 
    public string Product { get; set; } 
    public string Price { get; set; } 
} 

internal class ProfessionalDetails 
{ 
    public DateTime HireDate { get; set; } 
    public string Designation { get; set; } 
} 

internal class NameDetails 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

的基本邏輯是對於兩種方法是相同的。初始化類型是唯一被改變的東西。方法的返回值和要初始化的屬性/域會改變,但參數保持不變。

如何爲下面的方法使用一個單一的通用方法並決定在運行時初始化的類型?

+0

讓我把上面的另一種方式。只有一種通用方法而不是幾種具有相同邏輯的方法是一個好主意,這當然更簡單 –

回答

1

你可以寫這樣的事情:

private static T ThingFiller<T>(
    XNode context, 
    string elementStr, 
    params Action<Func<string, string>, T>[] setters 
) 
    where T : new() 
{ 
    var element = context.XPathSelectElement(elementStr); 
    var t = new T(); 

    foreach (var setter in setters) 
     setter(element.GetElementAsString, t);  

    return t; 
} 

private static NameDetails GetsNameDetails(XNode content) 
{ 
    return ThingFiller<NameDetails>(content, "document/employee/name", 
     (func, nd) => nd.FirstName = func("firstName"), 
     (func, nd) => nd.LastName = func("lastName") 
    ); 
} 

或者,你可以使用一個XML庫,並簡單地定義如何通過屬性和映射滿山遍野。

0

你可以添加一個泛型類型,然後根據類型決定要如何解析節點:

private static T GetsDetails<T>(XNode content) 
{ 
    if(typeof(T) == typeof(ProjectDetails)){ 
     var element = content.XPathSelectElement("document/employee/projects/project"); 

     return (T)new Projects 
     { 
      Id = element.GetElementAsString("id"), 
      Price = element.GetElementAsString("price"), 
      Product = element.GetElementAsString("product") 
     }; 
    } 
    else if(typeof(T) == typeof(ProfessionalDetails){ ... } 
    else if (...) {...} 
} 

我不會,雖然推薦這種方法:你還要做類型檢查和你獲得的很少。你擁有的初始實現要簡單得多。

0

您可以創建一個屬性來確定應該使用哪個XPath表達式。例如:

[XPathSelector("document/employee/projects/project")] 
internal class Projects 
{ 
    public int Id { get; set; } 
    public string Product { get; set; } 
    public string Price { get; set; } 
} 

,然後你可以通過反射使用這個(代碼是未經測試,可在這裏沒有C#編譯器):

private static T GetNode<T>(XNode content) 
    : where T : new() 
{ 
    var selector = typeof(T).GetCustomProperty<XPathSelector>(); 
    var element = content.XPathSelectElement(selector.XPathSelector); 

    var ret = new T(); 

    foreach (var child in element.Elements) { 
     var property = typeof(T).GetProperties().Single(p => p.Name.ToLower() == child.Name.ToLower()); 

     property.SetValue(ret, child.GetElementAsString(child.Name)); 
    } 

    return ret; 
} 
相關問題