В C # как реализовать абстрактный класс, который вызывает себя в функции, например, такой как класс Addable объектов? - PullRequest
0 голосов
/ 06 февраля 2019

Скажем, мы хотим определить класс, который допускает базовую арифметику, называемую «Addable».Добавляемые вещи могут быть добавлены.

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

Как правильно реализовать Addable?Следующее не работает, оно дает:

Число не реализует унаследованный абстрактный член 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: С учетом обратной связи этот вопрос, похоже, смещается в область " Интерфейс против Базового класса ".Возможно, другие, кто читает этот вопрос, могут найти этот вопрос осветительным.

Я надеюсь, что вопрос ясен, я новичок в SO, и хотя я старался придерживаться руководящих принципов, насколько это возможно, я буду радизмените вопрос, чтобы сделать его более понятным.

Ответы [ 3 ]

0 голосов
/ 06 февраля 2019

Все зависит от того, зачем вам нужен базовый класс Addable и как он будет использоваться.Стоит обновить ваш вопрос, чтобы объяснить это.Вот одна возможность, которая может не соответствовать вашему варианту использования:

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

Вы, конечно, можете использовать абстрактный базовый класс и здесь, если в этом есть необходимость:

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, так что это метод экземпляра, который добавляет себя к другомуinstance.

Если вы хотите сохранить подпись как 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, ...);
0 голосов
/ 06 февраля 2019

Вы можете сделать это:

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);
     }
}
0 голосов
/ 06 февраля 2019
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 класс является производным от Addable, вы все равно можете вызывать метод без приведения.


EDIT:

Оглядываясь назадв коде многое можно улучшить здесь.

Например, вы выставляете переменную (Value) - это противоречит законам инкапсуляции (OOP).Я бы предложил использовать свойство в этом случае.Кроме того, как уже упоминалось в комментариях (я упустил этот факт), свойство должно идти в вашем базовом классе.

Говоря о базовом классе, в этом случае было бы целесообразно включить это винтерфейсу, поскольку вы ничего не реализуете, а только декларируете.

Используйте интерфейс, когда хотите раскрыть план чего-либо.Используйте абстрактный класс, когда хотите раскрыть рамки чего-либо.

По сути, вы можете придумать интерфейс, подобный плану здания (чертежу) дома.Он объявляет структуру указанного дома.Думайте об абстрактном классе как о каркасе дома.Он еще не закончен, но вы можете стоять внутри стен и быть сухим - АКА, он уже предоставляет некоторые функциональные возможности.

Вот идея, как решить вашу проблему.Это не самое элегантное, но оно должно дать вам общее представление.

На самом деле, после того, как это записано, пришло в голову гораздо более изящное решение: использование структур.

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

Как уже упоминали другие в своих ответах, вы также можете использовать дженерики для учета большего количества типов данных.Неявные операторы (как в моем примере) , а не , обязательно лучший вариант для использования, особенно если вы только начинаете изучать язык.

...