实现加法与泛型
随着结构继承类..实现加法与泛型
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”。有任何想法吗?
你需要改变你的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.");
}
}
如果您的层次结构足够稳定,可以使用访问者模式的想法拿出这样的:
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
。
StackOverflowException!如果你没有匹配类型,运行时只能匹配Unit过载的调用,而不能匹配Weight或Measure过载,所以它会一直重复Add(Unit),直到... boom。 IMO比类型检查更糟糕;至少如果那个barf你知道发生了什么事情。国有企业是一种痛苦。 – KeithS 2010-09-03 21:44:14
在这种情况下'StackOverflowException'不会发生。没有递归调用。这些调用将被解析为正确的派生类的方法。派生类中的'this'是指派生类本身,而不是它的基类。这种模式用于实现[double-dispatch](http://en.wikipedia.org/wiki/Double_dispatch)。 – 2010-09-04 01:59:03
我其实从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();
}
}
如果你绝对必须使用基类的两个列表:
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()方法一起使用,将是类型安全的,因此不会抛出任何运行时异常。不好;您创建的任何新单元都需要添加更多代码来处理每种新类型。
我的单元类必须参与EntityConfiguration。所以我不能让它成为一个通用类型。有没有其他方法?哦,我明白了 - 你增加了另一种方式。我认为这可能有效。让我尝试一下并找出答案。 –
Ciel
2010-09-03 19:59:31
@Stacey - 我的选择应该在'Unit'类中工作。所以你不需要把它抽象化。 – GenericTypeTea 2010-09-03 20:06:14