Почему в С# существуют абстрактный класс и интерфейс?

Почему оба абстрактного класса и интерфейса существуют в С#, если мы сможем достичь функции интерфейса, сделав все члены класса абстрактными.

Это потому, что:

  1. Существует интерфейс для множественного наследования
  2. Имеет смысл иметь интерфейс, поскольку объект CAN-DO объекта должен быть помещен в абстрактный абстрактный класс интерфейса.

Просьба уточнить

Ответ 1

Ну, абстрактный класс может указать некоторую реализацию, но обычно не все. (Сказав, что вполне возможно обеспечить абстрактный класс без абстрактных членов, но множество виртуальных, которые с реализацией "no-op" ). Интерфейс не обеспечивает реализацию, а всего лишь контракт.

Вы могли бы, конечно, утверждать, что если разрешено множественное наследование классов, интерфейсы будут в основном бессмысленными.

Лично я не зацикливаюсь на целом "различие" для наследования "is-a" vs "can-do". Это никогда не дает мне столь же хорошей интуиции, что делать, как просто играть с разными идеями и видеть, какие из них чувствуют себя наиболее гибкими. (Опять же, я очень люблю "благосклонную композицию по наследству"...)

EDIT: так же, как самый удобный способ опровержения третьего пункта lbushkin в его комментарии... вы можете переопределить абстрактный метод с не-виртуальным (с точки зрения того, что он не может его переопределить), запечатывая его:

public abstract class AbstractBase
{
    public abstract void Foo();
}

public class Derived : AbstractBase
{
    public sealed override void Foo() {}
}

Классы, происходящие из Derived, не могут более переопределить Foo.

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

Ответ 2

Это не тривиальный вопрос, это очень хороший вопрос, и я всегда спрашиваю всех кандидатов, которых я собеседования. В двух словах - абстрактный базовый класс определяет иерархию типов, тогда как интерфейс определяет контракт.

Вы можете видеть это как есть vs реализует a.
т.е. Account может быть абстрактной базовой учетной записью, так как вы могли бы иметь CheckingAccount, a SavingsAccount и т.д. все, что вытекает из абстрактного базового класса Account. Абстрактные базовые классы также могут содержать не абстрактные методы, свойства и поля, как и любой нормальный класс. Однако интерфейсы только содержат абстрактные методы и свойства, которые должны быть реализованы должны.

С# позволяет вам получить только один базовый класс - одно наследование, как java. Однако вы можете реализовать столько интерфейсов, сколько хотите - это потому, что интерфейс - это просто контракт, который должен реализовать ваш класс promises.

Итак, если бы у меня был класс SourceFile, то мой класс мог бы выбрать реализацию ISourceControl, в котором говорится: "Я с честью обещаю реализовать методы и свойства, которые требуется ISourceControl

Это большая область и, вероятно, заслуживает лучшего поста, чем тот, который я дал, но я слишком короткий, но надеюсь, что это поможет!

Ответ 3

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

Абстрактный класс более мощный, чем интерфейс, в том смысле, что он позволяет мне создавать интерфейс наследования через абстрактные и виртуальные элементы, но также предоставляет некоторую стандартную или базовую реализацию, если я так хочу. Однако, как известно Человеку-паук, эта великая сила несет большую ответственность, поскольку абстрактный класс более архитектурно хрупкий.

Примечание: Интересно отметить, что Vance Morrrison (из команды CLR) предположил о добавлении реализаций метода по умолчанию к интерфейсам в будущей версии CLR. Это сильно размывает различие между интерфейсом и абстрактным классом. Подробнее см. это видео.

Ответ 4

Одна важная причина, по которой оба механизма существуют, поскольку С#.NET допускает только одно наследование, а не множественное наследование, такое как С++. Наследование класса позволяет наследовать реализацию только из одного места; все остальное должно быть выполнено путем реализации интерфейсов.

Например, предположим, что я создаю класс, например Car and я subclass, в три подкласса: RearWheelDrive, FrontWheelDrive и AllWheelDrive. Теперь я решаю, что мне нужно вырезать свои классы по другой "оси", как те, у кого есть кнопки и без них. Я хочу, чтобы все пусковые автомобили с кнопочным приводом имели метод PushStartButton() и не-кнопочные автомобили с методом "TurnKey()", и я хочу иметь возможность обрабатывать объекты автомобилей (в отношении их запуска), независимо от того, какой подкласс они есть. Я могу определить интерфейсы, которые могут реализовать мои классы, такие как IPushButtonStart и IKeyedIgnition, поэтому у меня есть общий способ обработки моих объектов, которые отличаются тем, что не зависит от одного базового класса, из которого каждый получает.

Ответ 5

Ты уже дал хороший ответ. Я думаю, что ваш второй ответ - настоящая причина. Если бы я хотел создать объект Compareable, мне не следовало бы выводить из базового класса Comparable. если вы думаете обо всех интерфейсах, подумайте обо всех перестановках, которые вы использовали для обработки основных интерфейсов, таких как IComparable.

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

Ответ 6

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

Ответ 7

Интерфейс определяет контракт, который должен выполнить класс реализации; это способ заявить, что "это делает это". Абстрактный класс - это частичная реализация класса, который по определению неполный и нуждается в завершении. Они совсем разные.

Ответ 8

An abstract class может иметь реализацию, а interface просто позволяет вам создать контракт, которому должны следовать исполнители. С абстрактными классами вы можете обеспечить общее поведение для своих подкласс, ведь вы не можете с интерфейсами.

Ответ 9

Они служат в двух совершенно разных целях.

Абстрактные классы предоставляют способ наследования объекта на основе определенного контракта, а также позволяют указывать поведение в базовом классе. Это, с теоретической точки зрения, обеспечивает связь IS-A в том, что конкретный класс IS-A определенного типа базового класса.

Интерфейсы позволяют классам определять (или более одного) контракт, который они будут выполнять. Они допускают ACTS-AS или "могут использоваться как" тип отношения ", а не прямое наследование. Вот почему, как правило, интерфейсы будут использовать прилагательное, поскольку они являются именем (IDisposable) вместо существительного.

Ответ 10

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

Например, интерфейс IEnumerable<T> описывает, что класс может выполнять итерацию через него, но он также ограничивает доступ к этой единственной способности. A List<T> также может обращаться к элементам по индексу, но когда вы обращаетесь к нему через интерфейс IEnumerable<T>, вы знаете только об этой способности итерации членов.

Если метод принимает интерфейс IEnumerable<T> как параметр, это означает, что он только перепробовал возможность итерации через члены. Вы можете использовать несколько разных классов с этой способностью (например, List<T> или массив T[]) без необходимости использования одного метода для каждого класса.

Мало того, что метод допускает несколько разных классов, реализующих интерфейс, вы можете создавать новые классы, реализующие интерфейс, и метод также с радостью примет их.

Ответ 11

Рассмотрим класс Плод, который выводится двумя детьми (Apple и Банана), как показано ниже:

class Fruit
{
    public virtual string GetColor()
    {
        return string.Empty;
    }
}

class Apple : Fruit
{
    public override string GetColor()
    {
        return "Red";
    }
}

class Banana : Fruit
{
    public override string GetColor()
    {
        return "Yellow";
    }
}

У нас есть существующий интерфейс ICloneable в С#. Этот интерфейс имеет один метод, как показано ниже, класс, реализующий этот интерфейс, гарантирует, что он может быть клонирован:

public interface ICloneable
{
    object Clone();
}

Теперь, если я хочу сделать класс Apple (не Banana) клонированным, я могу просто реализовать ICloneable следующим образом:

 class Apple : Fruit , ICloneable
{
    public object Clone()
    {
        // add your code here
    }

    public override string GetColor()
    {
        return "Red";
    }
}

Теперь, рассматривая ваш аргумент чистого абстрактного класса, если С# имел чистый абстрактный класс, скажите Clonable вместо интерфейса IClonable следующим образом:

abstract class Clonable
{
    public abstract object Clone();
}

Теперь вы можете сделать свой класс Apple клонированным, наследуя абстрактную Clonable вместо IClonable? например:

// Error: Class 'Apple' cannot have multiple base classes: 'Fruit' & 'Clonable'
class Apple : Fruit, Clonable
{
    public object Clone()
    {
        // add your code here
    }

    public override string GetColor()
    {
        return "Red";
    }
}

Нет, вы не можете, потому что класс не может быть получен из нескольких классов.