在 C# 中,如何实现一个在函数中调用自身的抽象 class,例如例如 class 个 Addable 对象?

In C#, how does one implement an abstract class that calls itsself in a function e.g. such as a class of Addable objects?

假设我们要定义一个允许基本算术的 class,称为 'Addable'。可以添加的东西。

abstract class Addable
{
   public abstract Addable Add(Addable X, Addable Y)
}

实现 Addable 的正确方法是什么?以下不起作用,它给出:

Number does not implement inherited abstract member Addable.Add(Addable, Addable).

class Number : Addable
{
     public int Value;

     public Number(int Val)
     {
        Value = Val;
     }

     public Number Add(Number X, Number Y)
     {
         return new Number(X.Value + Y.Value);
     }
}

我认为问题是 Add 将 (Number,Number) 作为参数,不够通用,但我不知道如何进行。

编辑:由于有些人要求知道这是做什么用的,所以让我详细说明一下。 我正在使用一种算法,该算法依赖于获取多个对象的最大值。根据用例,这些对象是数字或分布。为了继续上面的例子,我会假装我需要添加这些数字或分布。所以我想要的代码看起来像:

Addable LongAlgorithm(Addable X, Other parameters)
{
   ... // Lots of code that may contain X
   Z = Add(X,Y)
   ... // Code Using Z.

   return Answer // Answer is of the same type as X in the input.
}

编辑 2:根据给出的反馈,这个问题似乎进入了“Interface vs Base class”的境界。也许阅读此问题的其他人可能会发现该问题很有启发性。

希望问题清楚,我是 S.O 的新手。尽管我已尽力遵守指南,但我很乐意修改问题以使其更清楚。

class Number : Addable
{
     public int Value;

     public Number(int Val)
     {
        Value = Val;
     }

     public Number Add(Number X, Number Y)
     {
         return new Number(X.Value + Y.Value);
     }
}

需要

class Number : Addable
{
     public int Value;

     public Number(int Val)
     {
        Value = Val;
     }

     public override Number Add(Addable X, Addable Y)
     {
         return new Number(X.Value + Y.Value);
     }
}

当你声明一个抽象方法时,你需要完全按照声明的方式实现它,否则将无法编译。 但是不用担心,因为你的 Number class 派生自 Addable,你仍然可以在不强制转换的情况下调用该方法。


编辑:

回顾代码,这里有很多可以改进的地方。

例如,您公开了一个变量 (Value) - 这违反了封装法则 (OOP)。在这种情况下,我建议使用 属性。 另外,正如评论中提到的(我忽略了这个事实),属性 必须进入你的基础 class.

说到基础 class,在这种情况下,将其转换为接口是明智的,因为您没有实现任何东西,只是声明。

当你想公开某物的蓝图时使用接口。当你想公开某物的框架时,使用抽象 class。

本质上,您可以将界面想象成房屋的建筑平面图(蓝图)。它声明了所述房屋的结构。 将抽象 class 想象成房子的框架。它还没有完全完成,但你通常可以站在墙内并且会很干燥 - 也就是说它已经暴露了一些功能。

这是解决您的问题的方法。它不是最优雅的,但它应该给你一个大概的想法。

事实上,在写下这些之后,我想到了一个更优雅的解决方案:使用结构。

public interface IAddable {

    /// <summary >
    /// This is the value we want.
    /// </summary>
    int Value { get; set; }

    IAddable Add(IAddable x, IAddable y);

}

public class Number : IAddable {

    public Number() { }

    public Number(int num) => Value = num;

    public int Value { get; set; }

    public IAddable Add(IAddable x, IAddable y) {
        return (Number)(x.Value + y.Value);
    }

    public static implicit operator Number(int num) => new Number(num);
    public static implicit operator Number(double num) => new Number((int)num);
    public static implicit operator int(Number num) => num.Value;
}

编辑 2

正如其他人在他们的回答中提到的,您还可以使用泛型来解释更多数据类型。 隐式运算符(如我的示例中所用)不是 必然是最好的选择,尤其是在您刚刚开始学习该语言的情况下。

这完全取决于您想要 Addable 基础 class 的原因,以及它将如何使用。值得更新您的问题来解释这一点。这是一种可能不符合您的用例的可能性:

public interface IAddable<T>
{
    T Add(T x, T y);
}

public class Number : IAddable<Number>
{
    public int Value { get; set; }

    public Number(int value)
    {
        Value = value;
    }

    public Number Add(Number other)
    {
        return new Number(Value + other.Value);
    }
}

如果有需要,您当然也可以在这里使用抽象基础 class:

public abstract class Addable<T>
{
    public abstract T Add(T x, T y);
}

如果你想确保类型只能做class Foo : IAddable<Foo>而不能做class Foo : IAddable<Bar>,那么你可以添加一个泛型类型限制:

public interface IAddable<T> where T : IAddable<T>
{
    T Add(T x, T y);
}

回应您的编辑:

使用上面的类型并执行此操作:

T LongAlgorithm<T>(T x, Other parameters) where T : IAddable<T>
{
   ... // Lots of code that may contain x
   T z = x.Add(y);
   ... // Code Using z

   return z;
}

请注意,我已经更改了您的 Add 方法,使其成为一个实例方法,它将自身添加到另一个实例。

如果您想将签名保留为 Add(x, y),您可能需要这样的东西:

public class Number
{
    public int Value { get; set; }
    public Number(int value)
    {
        Value = value;
    }
}

public interface IAdder<T>
{
    T Add(T x, T y);
}

public class NumberAdder : IAdder<Number>
{
    public static readonly NumberAdder Instance = new NumberAdder();
    private NumberAdder() { }
    public Number Add(Number x, Number y)
    {
        return new Number(x.Value + y.Value);
    }
}

T LongAlgorithm<T>(T x, IAdder<T> adder, Other parameters)
{
   ... // Lots of code that may contain x
   T z = adder.Add(x, y);
   ... // Code Using z

   return z;
}

那就这样称呼吧

Number z = LongAlgorithm(new Number(3), NumberAdder.Instance, ...);

你可以做到:

abstract class Addable<T>
{
   public abstract T Add(T X, T Y);
}

class Number : Addable<Number>
{
     public int Value;

     public Number(int Val)
     {
        Value = Val;
     }

     public override Number Add(Number X, Number Y) 
     {
         return new Number(X.Value + Y.Value);
     }
}