2010-09-03 66 views
1

隨着結構繼承類..實現加法與泛型

abstract class Unit 
{ 
int Id; 
} 

class Measure : Unit 
{ 
int Current; 
int Baseline; 
} 

class Weight : Unit 
{ 
int Minimum; 
int Maximum; 
int Current; 
} 

我基本上要增加一個「添加」方法添加,比如,兩種方法一起使用,或添加兩個砝碼在一起。但它需要在Unit基類中。所以基本上,如果我有

List<Units> units = new List<Unit>(); 
List<Units> otherUnits = new List<Unit>(); 

// populate units with various Measures and Weights. 
// populate otherUnits with various Measures and Weights. 
foreach(Unit u in units) 
{ 
u.Add( 
     // add something from the otherUnits collection. Typesafe, etc. 
    ); 
} 

我已經試過..

public abstract T Add<T>(T unit) where T : Unit; 
在股類

,但我得到它是如何不是在繼承類的適當的標識符,當我嘗試錯誤用適當的類填充「T」。有任何想法嗎?

回答

4

你需要改變你的Unit抽象類採取了泛型類型:

abstract class Unit<T> 

然後你就可以添加Add抽象方法:

void Add(T unit); 

所以你的尺寸和重量的類將現在看如:

class Measure : Unit<Measure> 
class Weight : Unit<Weight> 

或者,添加th E採用抽象的方法來Unit

abstract void Add(Unit unit); 

然後你需要約束你的繼承類中使用這種類型檢查:

void Add(Unit unit) 
{ 
    if (unit.GetType() != this.GetType()) 
    { 
     throw new ArgumentException("You can only add measurements."); 
    } 
} 
+0

我的單元類必須參與EntityConfiguration 。所以我不能讓它成爲一個通用類型。有沒有其他方法?哦,我明白了 - 你增加了另一種方式。我認爲這可能有效。讓我嘗試一下並找出答案。 – Ciel 2010-09-03 19:59:31

+0

@Stacey - 我的選擇應該在'Unit'類中工作。所以你不需要把它抽象化。 – GenericTypeTea 2010-09-03 20:06:14

0

如果您的層次結構足夠穩定,可以使用訪問者模式的想法拿出這樣的:

abstract class Unit { 
    public abstract Unit Add(Unit unit); 
    public virtual Measure Add(Measure unit) { return unit; } 
    public virtual Weight Add(Weight unit) { return unit; } 
} 

class Measure : Unit { 
    public override Measure Add(Measure unit) { 
    // ... 
    } 
    public override Unit Add(Unit unit) { 
    return unit.Add(this); 
    } 
} 

class Weight : Unit { 
    public override Weight Add(Weight unit) { 
    // ... 
    } 
    public override Unit Add(Unit unit) { 
    return unit.Add(this); 
    } 
} 

你甚至可以使用一個真正的訪客,它從Unit分離如果您預計稍後將其他行爲添加到層次結構中,則可以使用該類。

注意:如果Add會更改當前實例,那麼如果應該返回void

+0

StackOverflowException!如果你沒有匹配類型,運行時只能匹配Unit過載的調用,而不能匹配Weight或Measure過載,所以它會一直重複Add(Unit),直到... boom。 IMO比類型檢查更糟糕;至少如果那個barf你知道發生了什麼事情。國有企業是一種痛苦。 – KeithS 2010-09-03 21:44:14

+0

在這種情況下'StackOverflowException'不會發生。沒有遞歸調用。這些調用將被解析爲正確的派生類的方法。派生類中的'this'是指派生類本身,而不是它的基類。這種模式用於實現[double-dispatch](http://en.wikipedia.org/wiki/Double_dispatch)。 – 2010-09-04 01:59:03

0

我其實從GenericTypeTea那裏得到了這個想法,但我想到了嘗試一種不同的方法。

public interface IUnit 
{ 
    T Add<T>(T unit) where T : IUnit<T>; 
} 

public interface IUnit<T> 
{ 
    T Add(T unit); 
} 

    abstract class Unit : IUnit 
    { 
    } 

    class Measure : Unit, IUnit<Measure> 
    { 
    public Measure Add(Measure unit) 
    { 
     throw new NotImplementedException(); 
    } 
    } 

    class Weight : Unit, IUnit<Weight> 
    { 
    public Weight Add(Weight unit) 
    { 
     throw new NotImplementedException(); 
    } 
    } 
0

如果你絕對必須使用基類的兩個列表:

public abstract class Unit() 
{ 
    public abstract Unit Add(Unit other); 

    public void MatchType(Unit other) 
    { 
     if(this.GetType() != other.GetType()) 
      throw new ArgumentException("Units not of same type"); 
    } 
} 

...然後實現每個派生類如下:

public override void Add(Unit other) 
{ 
    MatchType(other); 

    //actual implementation 
} 

然後擴展這個使用實際的Add實現實現派生類中的功能。

老實說,我沒有看到你想要做的事情。除非兩個列表僅包含Measures或僅包含Weights,否則它將不起作用,您只需將類型檢查置於Unit中即可隱藏該消息。這只是要求麻煩。

我會定義代碼你有這兩個列表中,如下所示:

public List<T> AddLists<T>(List<T> firstList, List<T> secondList) where T:Unit 
{ 
    //your code to add elements 
} 

...然後使用一個通用的Unit.Add()方法如下:

public static void Add<T>(this T item, T other) where T:Unit 
{ 
    //perform something that works like item += other 
} 

你」 d必須使用強度類型爲Weight或Measure的列表。您可以嘗試使用LINQ到列表的泛型參數轉換:

listOfMeasures = listOfUnits.OfType<Weight>().ToList(); 

當然,這將導致權重被過濾掉的名單,但是這可以工作,你的優勢:

listOfWeights = listOfUnits.OfType<Weight>().ToList(); 
listOfMeasures = listOfUnits.OfType<Measure>().ToList(); 

var addedListOfMeasures = AddLists(listOfMeasures, otherListOfMeasures); 
var addedListOfWeights = AddLists(listofWeights, otherListOfWeights); 

以上代碼,與我列出的通用AddLists和Unit.Add()方法一起使用,將是類型安全的,因此不會拋出任何運行時異常。不好;您創建的任何新單元都需要添加更多代碼來處理每種新類型。