2009-07-14 3 views
3

Допустит, у меня есть следующие C# классов:.net абстрактное переопределение причуда

abstract class a 
{ 
    protected abstract void SomeMethod(); 
} 

abstract class b : a 
{ 
    protected abstract override void SomeMethod(); 
} 

class c : b 
{ 
    protected override void SomeMethod() 
    { 

    } 
} 

Есть ли на самом деле любая точка переопределения метода в б, когда он может так же легко быть записан как:

abstract class b : a 
{ 
} 

Что было бы «предпочтительным» способом написания b? И если нет смысла переопределять абстрактный метод или свойство, почему это разрешено?

ответ

5

Одна из причин, по которой вы можете разрешить это: оно показывает намерение. В нем объясняется, что да, вы знаете, что этот метод является абстрактным в базовом классе. Я знаю это, и я еще хочу, чтобы он был абстрактным здесь.

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

Тем не менее, это не особенно важная причина ... Я бы, конечно, оставил это.

+0

Я не уверен, что понимаю ... в чем преимущество добавления еще одной точки компиляционного отказа? Кроме того, если ваш базовый класс добавляет еще один абстрактный метод и вы не реорганизуете свои производные, вы не получите этот результат последовательно. – LBushkin

+0

@LBushkin: Правда, вы не заметите добавления ...но добавление другой точки сбоя может оказаться полезным, если в противном случае у вас не было бы * any * (имея в виду, что у вас может не быть конкретного класса в любом месте вашей кодовой базы). Я не говорю, что это часто возникает ... –

+1

Любое описание в дереве наследования (decriptive code, или * значимые * комментарии). Наследование делает взаимодействие базового и производного классов немного загадочным - особенно если (а) базовый класс - это нечто иное, чем простой, хорошо спроектированный и сфокусированный объект (б), если сопровождающий не писал как базу, так и производный класс. Наследие замечательно, но может сильно злоупотреблять, чтобы сделать магически закопченный код – STW

0

Вам не нужно переопределять SomeMethod() в b. Абстрактный класс объявляет, что в нем могут быть неопределенные/абстрактные методы. Когда вы расширяете один абстрактный класс на другой, он неявно наследует любые абстрактные методы от родителя.

+0

. Разве это не означает, что класс становится абстрактным и не может быть создан без дочернего класса, который реализует этот метод? –

+0

Правильно, класс B также был бы абстрактным. C# требует, чтобы вы явно объявляли его абстрактным, а также предоставили вам ошибку компилятора, если вы этого не сделаете. – geofflane

2

Иметь a look at this blog. Иногда сочетания обоих полезно:

«Хороший дизайн языка обычно приводит несколько хорошо определенных простых примитивов, которые могут быть объединены вместе в интуитивных и умных способов В отличие от этого, бедный язык дизайн, как правило, приводит. многие раздутые конструкции, которые не играют хорошо вместе.

«абстрактное» и «Override» ключевые слова в C# являются отличным примером этого. Они оба имеют простые определения, но их можно комбинировать, чтобы выразить более сложную концепцию .

Допустим, у вас есть иерархия классов: C производный от B и B вытекает из А. имеет абстрактный метод Foo() и Goo(). Вот два сценария, в которых возникло бы «абстрактное переопределение» . 1) Предположим, что B только хочет реализовать Goo(), и пусть C реализует Foo(). B может помечать Foo() как "абстрактное переопределение". Это ясно говорит о том, что B распознает, что Foo() объявлен в базовом классе , но он ожидает, что другой класс будет реализован.

2) Предположим, что B хочет заставить C до повторно использовать Foo() вместо определения A определения Foo(). В отмечает Foo() в качестве и коррекции (что означает Б распознает Foo() объявляется в базовом классе) и абстрактные (что означает B силы производного класса С, чтобы обеспечить осуществления; независимо, что А уже обеспечили реализация). Это появилось в одном из моих недавних записей в блоге . В этом примере A = TextReader, Foo = ReadLine, B = a helper class, C = некоторый класс, который хочет, чтобы реализовал ReadLine() вместо Read(). Теперь у TextReader уже есть реализация по умолчанию для ReadLine() на основе Read(), но мы хотим пойти по пути . Мы хотим реализовать реализацию Read() на основе классов классов ReadLine(). Таким образом, В представляет собой реализацию Read(), который потребляет ReadLine(), а затем отмечает ReadLine() как «абстрактное переопределения», чтобы заставить C, чтобы переопределять ReadLine() вместо того, чтобы выбрать вверх по одному из TextReader.

В итоге, «абстрактное переопределение» является не круто, потому что это еще более одна особенности языка для выражения сложных углового случая; это классно, потому что это еще не одна особенность языка. Элегантная часть состоит в том, что вам не нужно подумать об этом. Вы просто использовать отдельные основные понятия естественно, и сложный материал поставляется вместе автоматически «

Это мой пример кода для сценария 1:.

public abstract class A 
{ 
    public abstract void Foo(); 
    public abstract void Goo(); 
} 

public abstract class B : A 
{ 

    public abstract override void Foo(); 

    public override void Goo() 
    { 
     Console.WriteLine("Only wanted to implement goo"); 
    } 
} 

public class C : B 
{ 

    public override void Foo() 
    { 
     Console.WriteLine("Only wanted to implement foo"); 
    } 
} 

И мой пример кода для сценария 2 :

public abstract class A 
{ 
    public virtual void Foo() 
    { 
     Console.WriteLine("A's Foo"); 
    } 
    public abstract void Goo(); 
} 

public abstract class B : A 
{ 

    public abstract override void Foo(); 

    public override void Goo() 
    { 
     Console.WriteLine("Only wanted to implement goo"); 
    } 
} 

public class C : B 
{ 

    public override void Foo() 
    { 
     Console.WriteLine("Forced to implement foo"); 
    } 
} 

В вашем вопросе код не так полезен, но это не значит, что абстрактные и переопределенные комбинированные i s не полезно.

2

Я обычно не повторно объявлять абстрактные методы, когда я на самом деле не намерены поставлять реализацию - по нескольким причинам:

  • Я не изменяет семантику кода.
  • Он добавляет еще одну вещь для рефакторинга, если базовый класс изменяется.
  • Это приводит к несогласованности новых абстрактных методов, которые добавляются в базовый класс, и вы не добавляете их в промежуточные классы.
  • Это довольно болезненно для иерархии классов с более чем несколькими уровнями.
  • Он загромождает ваш код декларацией, которая добавляет мало значения.
2

В дополнение к уже сказал:

override также может быть использован для объявить атрибуты, которые не определены в базовом классе. Если все еще не имеет реализации, это будет абстрактное переопределение.

abstract class b : a 
{ 
    [SomeAttribute] 
    protected abstract override void SomeMethod(); 
} 
+0

Это хороший момент. В качестве побочной проблемы, если DataMember является System.Runtime.Serialization.DataMemberAttribute, ваш код не будет компилироваться. Я думаю, что люди понимают эту идею. – RichardOD

+0

Хорошо, просто взял первый атрибут, который пришел мне на ум :-) исправил его. –

Смежные вопросы