2014-01-22 42 views
1

我不確定在C#中建模的最佳方式是什麼,我將嘗試解釋我想要做什麼。我連接到一個SOAP API(我無法控制),它返回幾種類型的實體。對於所有實體以及特定於某些類型的實體的其他一些實體,都有一些共享字段。實際上在任何常規繼承結構中都有幾個級別。展開子類中的父列表

當我通過API請求一個實體時,無論類型如何,我都必須發送我想要的字段列表和實體類型,然後我返回一個帶有這些字段值列表的通用實體對象。

我想重新創建我的其他系統中的原始類,保持繼承結構。我希望我的類具有特定於它們的字段的列表,以及特定於它們所繼承的父級的字段的列表。事情是這樣的:

public class BaseEntity 
{ 
    public virtual IEnumerable<string> Fields 
    { 
     get { return new List<string> {"field1"}; } 
    } 
} 

public class ChildEntity:BaseEntity 
{ 
    public virtual IEnumerable<string> Fields 
    { 
     get 
     { 
      var fields = new List<string> {"field2"}; 
      fields.AddRange(base.Fields); 
      return fields; 
     } 
    } 
} 

像這樣的工作,或多或少,考慮到子類刪除父領域的風險(但將通過不假設你不能爲空部分進行清理整頓屬性中的值和處理)。這就是請求部分的樣子:

ApiRequest request = new ApiRequest() 
request.Id = "1"; 
request.Type = "ChildEntity"; 
request.Fields = ChildEntity.Fields // This is what I want to get dynamically somehow 
RemoteEntity remoteEntity = apiClient.Request(request); 
ChildEntity childEntity = new ChildEntity(remoteEntity); // It parses the expected values 

但是,字段列表實際上應該是靜態的。我想在向服務器發送字段請求之前訪問它,所以我沒有任何類實例,因此我不能使用這個繼承解決方案。你會建議什麼?

回答

0

我終於決定爲此使用自定義屬性。我認爲這是一種更優雅和可維護的解決方案,因爲我沒有孩子班覆蓋父母領域的風險。

[EntityFields("field1","field2")] 
public class BaseEntity 
{ 
    public ISet<string> Fields 
    { 
     get 
     { 
      Type typeToCheck = GetType(); 
      ISet<string> fields = new HashSet<string>(); 

      do 
      { 
       var entityFieldsAttribute = 
        (EntityFields) Attribute.GetCustomAttribute(typeToCheck, typeof (EntityFields)); 
       if (entityFieldsAttribute != null) 
       { 
        fields.UnionWith(entityFieldsAttribute.Fields); 
       } 
       typeToCheck = typeToCheck.BaseType; 
      } while (typeToCheck != typeof (BaseEntity)); 

      return fields; 
     } 
    } 
} 

[EntityFields("field3","field4")] 
public class ChildEntity:BaseEntity 
{ 

} 
0

這裏有幾個方法可以做到這一點:

1:明確定義字段的繼承關係,一拉:

public class BaseEntity 
{ 
    protected static readonly string[] fields = { "field1" }; 
    public static IEnumerable<string> Fields 
    { 
     get { return fields; } 
    } 
} 

public class ChildEntity : BaseEntity 
{ 
    protected static readonly string[] fields = { "field2" } ; 
    public static IEnumerable<string> Fields 
    { 
     get { return BaseEntity.Fields.Concat(fields); } 
    } 
} 

public class GrandChildEntity : ChildEntity 
{ 
    protected static readonly string[] fields = { "field3" } ; 
    public static IEnumerable<string> Fields 
    { 
     get { return ChildEntity.Fields.Concat(fields); } 
    } 
} 

// Result: 
// BaseEntity.Fields == { "field1" }; 
// ChildEntity.Fields == { "field1", "field2" }; 
// GrandChildEntity.Fields == { "field1", "field2", "field3" }; 

不那麼漂亮或超高效,但比其略好明確定義每個班級的整個清單fields

2:使用反射來直接獲取存在於每個類屬性的列表,並刪除所有未實際域的API對象模型的那些:

public class BaseEntity 
{ 
    private static readonly string[] fields = System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType.GetProperties().Select(p => p.Name).Where(name => !name.Equals("Fields")).ToArray(); 
    public static IEnumerable<string> Fields { get { return fields; } } 
    public object field1 { get; set; } 
} 

public class ChildEntity : BaseEntity 
{ 
    private static readonly string[] fields = System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType.GetProperties().Select(p => p.Name).Where(name => !name.Equals("Fields")).ToArray(); 
    public static IEnumerable<string> Fields { get { return fields; } } 
    public object field2 { get; set; } 
} 

public class GrandChildEntity : ChildEntity 
{ 
    private static readonly string[] fields = System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType.GetProperties().Select(p => p.Name).Where(name => !name.Equals("Fields")).ToArray(); 
    public static IEnumerable<string> Fields { get { return fields; } } 
    public object field3 { get; set; } 
} 
+0

我認爲這不適用於更多級別的繼承,因爲您正在對父類型進行編碼。此外,隱藏父方法,可能會導致問題,但可能不會在這種情況下,當我從最具體的類中獲取字段。 (還是)感謝你的建議。 – MaQy

+0

要獲取沒有類實例的字段數據,除了使用靜態成員之外別無選擇。我添加了使用反射的第二個示例,它避免直接引用父類,但仍使用靜態成員。 – agentnega

0

我想在我的其他系統中重新創建原始類別

Visual Studio可以通過Add Service Reference完成該操作。它會自動從目標Web服務生成代理類。這會讓你無法親自完成工作。

只需右鍵單擊您的項目並選擇添加服務引用。該對話框大多是不言自明的。

This link是一個簡單的操作方法(它提到了WCF,但您可以忽略它,它對於所有Web服務都是一樣的)。

+0

是的,我最初做到了這一點,但是Web服務只是爲所有實體公開泛型類,正如我試圖解釋的那樣。這就是爲什麼我想要一種繼承和擴展字段名稱從父母到孩子的方式,但我找不到這樣做的一個很好的方法(可維護且不容易出錯)。 – MaQy