在带有泛型的继承类中实现加法

发布于 2024-09-16 22:37:29 字数 792 浏览 9 评论 0原文

通过结构..

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.
      ); 
} 

在 Unit 类中尝试过 ..

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

,但是当我尝试用适当的类填充“T”时,我会收到关于它在继承类中不是适当标识符的错误。有什么想法吗?

With the structure..

abstract class Unit
{
 int Id;
}

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

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

I basically want to add an "Add" method for adding, say, two Measures together, or adding two Weights together. But it needs to be in the Unit base class. So basically if I had

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.
      ); 
} 

I have tried ..

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

in the Unit class, but I get errors about how it isn't an appropriate identifier in the inherited classes when I try to fill "T" with the appropriate class. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

定格我的天空 2024-09-23 22:37:30

我实际上是从 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();
    }
    }

I actually got the idea from GenericTypeTea, but it occurred to me to try a different method.

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();
    }
    }
远昼 2024-09-23 22:37:30

如果您绝对必须使用基类的两个列表:

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 实现在派生类中扩展此功能。

老实说,我不明白你想做的事情有什么意义。除非两个列表仅包含度量或仅包含重量,否则它不会起作用,并且您只是通过将类型检查放入单位来向消费者隐藏这一事实。那只是自找麻烦。

我将定义包含这两个列表的代码,如下所示:

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
}

您必须使用强类型化为“重量”或“测量”的列表。您可以尝试使用 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() 方法一起使用我布局,将是类型安全的,因此不会抛出任何运行时异常。并没有带来好处;您创建的任何新单元都需要添加更多代码来处理每种新类型。

If you absolutely had to be using two lists of the base class:

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");
    }
}

...then implement the following in each derived class:

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

   //actual implementation
}

then extend this functionality in your derived classes with the actual Add implementation.

Honestly, I do not see the point of what you're trying to do. It wouldn't work unless both lists contained only Measures or only Weights, and you're just hiding that fact from the consumer by putting type-checking into Unit. That's just asking for trouble.

I would define the code you have these two lists in as follows:

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

... then use a generic Unit.Add() method as follows:

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

You'd have to use lists strongly typed to Weight or Measure. You can try to convert a List's generic parameter using Linq:

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

Of course this will cause Weights to be filtered out of the list, but this can work to your advantage:

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

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

The above code, used with the generic AddLists and Unit.Add() methods I laid out, will be type-safe and thus won't throw any runtime exceptions. Doesn't make it good; any new Unit you create will require adding more code to this to handle each new type.

你如我软肋 2024-09-23 22:37:29

您需要更改您的 Unit 抽象类以采用泛型类型:

abstract class Unit<T>

然后您可以添加 Add 抽象方法:

void Add(T unit);

因此您的测量和重量类现在如下所示:

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

或者,将以下抽象方法添加到 Unit 中:

abstract void Add(Unit unit);

然后您需要在继承类中使用类型检查来约束它:

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

You need to change your Unit abstract class to take a generic type:

abstract class Unit<T>

Then you can add the Add abstract method:

void Add(T unit);

So your measurement and weight classes will now look like:

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

Alternatively, add the following abstract method to Unit:

abstract void Add(Unit unit);

And then you'll need to constraint this using type checking within your inheriting class:

void Add(Unit unit)
{
    if (unit.GetType() != this.GetType())
    {
        throw new ArgumentException("You can only add measurements.");
    }
}
最终幸福 2024-09-23 22:37:29

如果你的层次结构足够稳定,你可以使用访问者模式的想法来提出这样的想法:

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

If your hierarchy is stable enough, you can use the visitor pattern idea to come up with something like this:

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);
  }
}

You can even use a true visitor and separate it from the Unit class if you anticipate other behaviors to be added to the hierarchy later.

Note: if Add will change the current instance, then if should return void.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文