2010-09-05 159 views
1

首先要注意 - 我知道代表和裝飾圖案!班級延伸 - 最佳做法/最佳解決方案

第二 - 我正在使用C#.NET 4.0,所以如果你想出一個特定的解決方案,那很好。但如果解決方案適用於任何OOP語言和平臺,那就太好了。

而且這裏的問題去...

我有一個分部類(允許其命名爲Class1),我不能修改。因此,我可以擴展它或/並從中繼承。這個類爲我提供了一個完美的數據模型,我唯一需要的是爲它的屬性添加一些屬性(用於驗證,在MVC等中定義標籤文本值 - 現在,我不需要像'你可以做什麼需要沒有屬性「,這不是我的問題)。

使用另一個類作爲數據模型不是問題,所以我可以創建Class2 : Class1並使用Class2作爲模型。需要屬性的屬性將被定義爲public new <type> <propertyname>。這將限制我只重寫需要屬性的屬性,而不會改變所有其他屬性。

較小的問題是,我不怎樣重新定義getter和setter屬性,因爲他們所要包含的return base.<propertyname>base.<propertyname> = value,如果有大量的這種特性,這意味着大量的「笨」的編碼。有沒有辦法避免這種情況?

更大的問題是,我有我的參數化與Class2例如Class1和製造類似class2.<propertyname> = class1.<propertyname>每個單一的財產我有 - 太多的「笨」的編碼。我可以使用反射來避免它 - 在公共獲取者和設置者中找到所有屬性,在Class1中,並在循環中調用prop.SetValue(child, prop.GetValue(parent, null), null);。這爲簡單的情況提供了一個通用的功能,這很好,因爲我大多數都有簡單的模型 - 大量的公有getter和setter沒有body和另一個邏輯的屬性。但我想要更通用的解決方案,而且我不喜歡反思。有任何想法嗎?

這裏去創建Class2基礎上Class1

public static Child ToExtendedChild<Parent, Child>(this Parent parent) 
     where Child : Parent, new() 
    { 
     Child child = new Child(); 

     var props = typeof(Parent).GetProperties().Where(p => p.GetAccessors().Count() >= 2); 

     foreach (var prop in props) 
     { 
      prop.SetValue(child, prop.GetValue(parent, null), null); 
     } 

     return child; 
    } 

擴展方法的完整代碼(順便說一下,這種方法可能不理想實現我的解決方案,所以任何糾正可能還可以理解的)

提前致謝!

回答

2

較小的問題似乎沒有太大的問題。也許我誤解了這個問題,但假設你只是派生一個子類,那麼就沒有理由重新定義這些屬性或者它們相關的getter/setter。

更大的問題可能會解決使用一些簡單的事情。使用反射進行很多對象初始化似乎有點貴。如果您正在處理一個主要是大包或物業的課程,也許您應該好像在任何特定情況下都需要訪問這些屬性的所有。你提到MVC和驗證,是你正在驗證的控制器方法中使用的整個模型?如果沒有,爲什麼不使用視圖模型只顯示那些你需要的方法?

你的反射初始化器很有趣,但如果你要做很多這個,那麼你可以考慮投資一點時間Automapper。否則,可以考慮從通用解決方案轉移到剛剛解決手頭問題的方法,即將屬性從對象的實例映射到派生對象的另一個實例。也許你可以在父類中創建一個複製構造函數並在派生類中使用它?

public class Foo { 
    public string PropOne { get; set; } 
    public string PropTwo { get; set; } 

    public Foo(string propOne, string propTwo) { 
     PropOne = propOne; 
     PropTwo = propTwo; 
    } 

    public Foo(Foo foo) { 
     PropOne = foo.PropOne; 
     PropTwo = foo.PropTwo; 
    } 
} 

public class Pho : Foo { 
    // if you have additional properties then handle them here 
    // and let the base class take care of the rest. 
    public string PropThree { get; set; } 
    public Pho(string propOne, string propTwo, string propThree) 
     : base(propOne, propTwo) { 
     PropThree = propThree; 
    } 
    public Pho(Pho pho) : base(pho) { 
     PropThree = pho.PropThree; 
    } 
    // otherwise you can just rely on a copy constructor 
    // to handle the initialization. 
    public Pho(Foo foo) : base(foo) {} 
} 
+0

我必須重新定義getters和setter,因爲我正在製作屬性'new',並且複製構造函數只是寫了很多行的另一種變體,如'property = property' – 2010-09-06 07:42:05

+0

並感謝AutoMapper - 這很有趣,雖然我不確定我想導入第三方解決方案來解決這個小問題。 – 2010-09-06 07:50:20

1

我假設分部類是生成代碼,它給你的場景最有意義。

我知道一種方法可以做到這一點,但取決於屬性如何被抓取,它可能無法正常工作。

// Generated Code 
public partial Class1 
{ 
    public string Foo { get { ... } } 
} 

// Your Code 
public interface IClass1 
{ 
    [MyAttribute] 
    public string Foo { get; } 
} 

public partial Class1 : IClass1 
{ 
} 

如果有人使用GetCustomAttributes與繼承看屬性,那麼我想他們會得到這個屬性。另外,每當我看到生成的代碼沒有虛擬屬性時,它就會讓我有點內心的哭泣。

爲了解決更大的問題,爲什麼不讓Class2成爲Class1的包裝。除了複製所有屬性外,您可以在構造函數中爲Class2提供Class1的實例,將其存儲在本地並使所有屬性都通過。它意味着一些手工編碼,但是如果你手動創建Class2並想用一些屬性來裝飾它,那麼無論如何你都是手動編碼Class2。

+0

我一定會嘗試一下你的界面方法,如果屬性確實是通過繼承進行爬網的話,那看起來會很棒。 – 2010-09-06 07:29:45

+0

使Class2成爲包裝並不是我正在尋找的東西,因爲在每個屬性的主體中,我都必須編寫'return class1。','class1。 = value',我想避免這種情況 - this意味着太多無用的編碼。我的方法看起來很相似,但我只爲那些需要屬性的屬性定義了主體 - 這可能會在某些情況下產生變化。無論如何,如果接口方法有效,我更大的問題可能只會成爲一個理論問題。謝謝! – 2010-09-06 07:39:08