2010-09-03 82 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()方法一起使用,将是类型安全的,因此不会抛出任何运行时异常。不好;您创建的任何新单元都需要添加更多代码来处理每种新类型。