在 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);
}
}
假设我们要定义一个允许基本算术的 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);
}
}