2008-10-10 2 views
53

Я пришел через многочисленные аргументы против включения множественное наследование в C#, некоторые из которых включают (философские аргументы в сторону):Должен ли C# иметь множественное наследование?

  • Множественное наследование является слишком сложным и часто неоднозначны
  • Излишне, потому что интерфейсы обеспечивают нечто подобное
  • композиции является хорошей заменой, где интерфейсы неуместны

Я родом из фона C++ и пропустить мощь и элегантность множественного inhe ritance. Хотя это не подходит ко всем проектам программного обеспечения, существуют ситуации, когда трудно отрицать его полезность по интерфейсам, композиции и аналогичным методам OO.

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

Я лично приветствовал бы введение множественного наследования в C# (возможно, C##).


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

ответ

112

Я никогда не пропустил его один раз, а не когда-либо. Да, это [MI] усложняется, и да, интерфейсы выполняют подобную работу по-разному - но это не самая большая точка: в общем смысле она просто не нужна большую часть времени. Во многих случаях даже одно наследование чрезмерно используется.

+0

Я свежий Outta голосов, так считают это +1 – Rob 2008-10-10 14:51:38

+0

Ну, вы всегда можете вернуться через несколько часов ;-p – 2008-10-10 14:52:28

+0

Я слышал подобные аргументы от разработчиков, которые исходят из процедурного фона программирования. Их аргумент был бы «объектами, которые никогда не нуждались в них». Это не так. Если они более выразительны, они имеют ценность (в правильной ситуации). – 2008-10-10 14:58:38

1

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

Я не буду отрицать, что у него есть потенциал, но я просто не вижу достаточной выгоды.

11

C# поддерживает одно наследование, интерфейсы и методы расширения. Между ними они обеспечивают практически все, что обеспечивает множественное наследование, без головных болей, которые приносит множественное наследование.

+0

(за исключением, может быть, состояние от нескольких предков .. но я с вами на этом; -p) – 2008-10-10 14:56:39

+0

@ Маркс, черт возьми, я знал, что мое радикальное обобщение вернется, чтобы укусить меня. Отредактировано немного, чтобы покрыть вашу точку :) – 2008-10-10 14:59:21

+2

Аналогичные, но не то же самое. Я бы также утверждал, что методы расширения приходят с их собственным вкусом сложности. Я думаю, что у CodingHorror был пост. – 2008-10-10 15:01:03

5

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

+0

Microsoft сделала подобные предположения, когда представила VB. Они предположили, что разработчики недостаточно умен, чтобы создавать хороший код, поэтому язык был заглушен соответствующим образом. Я лично нашел это наступление и ушел от VB и к более выразительным языкам. – 2008-10-10 15:04:00

+0

Тем не менее, VB.Net теперь расширился до такой степени, что в нем все функции C#. – Kibbee 2008-10-10 15:12:12

1

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

2

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

36

Предпочитаете агрегацию над наследованием!

class foo : bar, baz 

часто лучше обращаться с

class foo : Ibarrable, Ibazzable 
{ 
    ... 
    public Bar TheBar{ set } 
    public Baz TheBaz{ set } 

    public void BarFunction() 
    { 
    TheBar.doSomething(); 
    } 
    public Thing BazFunction(object param) 
    { 
    return TheBaz.doSomethingComplex(param); 
    } 
} 

Таким образом, вы можете поменять в и из различных реализаций IBarrable и IBazzable для создания нескольких версий приложения без необходимости писать еще один класс.

Зависимость от инъекции может помочь в этом.

2

Множественное наследование в целом может быть полезным, и многие языки OO реализуют его так или иначе (C++, Eiffel, CLOS, Python ...). Это важно? Нет. Приятно ли иметь? Да.

2

Update
Я призываю всех, кто голосует за меня, чтобы показать мне какой-либо пример множественного наследования, что я не могу легко переносить на язык с одинарным наследованием. Если кто-либо не может показать такой образец, я утверждаю, что его не существует. Я портировал тонны кода C++ (MH) на Java (no-MH), и это никогда не было проблемой, независимо от того, сколько MH использует код C++.


Никто не мог доказать, до сих пор, что множественное наследование имеет any advantage сравнению с другими способами вы упомянули в своем сообщении (с использованием интерфейсов и делегатов я могу получить точно такой же результат без особого кода или накладных расходов), в то время как у него есть пара из хорошо известных недостатков (diamond problem является наиболее раздражающим).

На самом деле множественное наследование обычно злоупотребляют. Если вы используете OO-дизайн для того, чтобы каким-то образом моделировать реальный мир в классах, вы никогда не дойдете до такой степени, что на самом деле имеет смысл множественное наследование. Можете ли вы предоставить полезный пример для множественного наследования? Большинство примеров, которые я видел до сих пор, на самом деле «ошибочны». Они делают что-то подклассом, это на самом деле просто дополнительное свойство и, фактически, интерфейс.

Взгляните на Sather. Это язык программирования, где интерфейсы имеют множественное наследование, так как почему бы и нет (он не может создать проблему с алмазом), однако классы, которые не являются интерфейсами, не имеют никакого наследования. Они могут реализовывать только интерфейсы, и они могут «включать» другие объекты, что делает эти другие объекты фиксированной частью из них, но это не то же самое, что наследование, это скорее форма делегирования (вызовы методов «унаследованы» путем включения объектов на самом деле просто перенаправлены на экземпляры этих объектов, инкапсулированных в ваш объект). Я думаю, что эта концепция довольно интересна, и она показывает, что вы можете иметь полный чистый язык OO без какого-либо наследования реализации.

+0

Я согласен, что имеет свои сложности (одна из них - проблема алмазов), но невозможно полностью выразить множественное наследование с помощью методов интерфейса, композиции или расширений (или некоторая комбинация там). – 2008-10-10 15:18:37

1

Я думаю, его простое на самом деле. Как и любая другая сложная парадигма программирования, вы можете злоупотреблять ею и причинять себе боль. Можете ли вы неправильно использовать объекты (о да!), Но это не значит, что OO плохо само по себе.

Аналогично МИ. Если у вас нет большого «дерева» унаследованных классов или много классов, которые предоставляют одинаковые именованные методы, тогда вы отлично справитесь с MI. На самом деле, поскольку MI обеспечивает реализацию, вам часто будет лучше, чем реализация SI, где вам нужно перекодировать, или вырезать & методы вставки для делегированных объектов. Меньше кода в этих случаях лучше. Вы можете сделать всемогущий беспорядок обмена кодом, пытаясь повторно использовать объекты через наследование интерфейса. И такие обходные пути не пахнут правильно.

Я думаю, что однонамерная модель .NET ошибочна: они должны были иметь только интерфейсы или только MI. Наличие «половины и половины» (т. Е. Одно наследование реализации плюс множественное наследование интерфейса) более сбивает с толку, чем должно быть, а не элегантно.

Я родом из MI-фона, и я не боюсь и не сгорел.

1

Я разместил это здесь пару раз, но я просто думаю, что это действительно круто. Вы можете узнать, как подделать MI here. Я также думаю, что в статье подчеркивается, почему МИ является такой болью, даже если это не было предназначено.

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

15

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

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

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

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

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

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

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

1

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

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

Вещи, которые я хотел бы увидеть, включают в себя некоторые функции Spec#, такие как ссылочные типы с нулевыми значениями. Я также хотел бы видеть больше безопасности объектов, имея возможность объявлять параметры как const и возможность объявлять функцию const (что означает, что вы гарантируете, что внутреннее состояние объекта не будет изменено методом и компилятор дважды проверяет вас).

Я думаю, что между Single Inheritence, Multiple Inheritence, Generics и Extension Methods вы можете делать практически все, что вам нужно. Если что-то может улучшить ситуацию для кого-то, желающего МИ, я думаю, что потребуется какая-то языковая конструкция, которая позволила бы упростить агрегацию и состав. Таким образом, вы можете иметь общий интерфейс, но затем делегируйте свою реализацию частному экземпляру класса, который вы обычно наследуете. Прямо сейчас, для этого требуется много кодовых табличек. Наличие более автоматизированной языковой функции для этого поможет значительно.

8

Множественное наследование не поддерживается CLR каким-либо образом, о котором я знаю, поэтому я сомневаюсь, что он может быть эффективно поддержан так, как на C++ (или Eiffel, что может сделать это лучше, язык специально разработан для ИМ).

Хорошая альтернатива множественному наследованию называется Черты. Это позволяет смешивать различные единицы поведения в один класс. Компилятор может поддерживать черты как расширение времени компиляции для системы с одним наследованием. Вы просто объявляете, что класс X включает в себя признаки A, B и C, а компилятор ставит те черты, которые вы просите вместе, чтобы сформировать реализацию X.

Например, предположим, что вы пытаетесь реализовать IList (of T) , Если вы посмотрите на различные реализации IList (из T), они часто используют один и тот же код. Это были черты. Вы просто объявляете черту с общим кодом, и вы можете использовать этот общий код в любой реализации IList (из T) - даже если в реализации уже есть некоторый другой базовый класс. Вот что синтаксис может выглядеть следующим образом:

/// This trait declares default methods of IList<T> 
public trait DefaultListMethods<T> : IList<T> 
{ 
    // Methods without bodies must be implemented by another 
    // trait or by the class 
    public void Insert(int index, T item); 
    public void RemoveAt(int index); 
    public T this[int index] { get; set; } 
    public int Count { get; } 

    public int IndexOf(T item) 
    { 
     EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
     for (int i = 0; i < Count; i++) 
      if (comparer.Equals(this[i], item)) 
       return i; 
     return -1; 
    } 
    public void Add(T item) 
    { 
     Insert(Count, item); 
    } 
    public void Clear() 
    { // Note: the class would be allowed to override the trait 
     // with a better implementation, or select an 
     // implementation from a different trait. 
     for (int i = Count - 1; i >= 0; i--) 
      RemoveAt(i); 
    } 
    public bool Contains(T item) 
    { 
     return IndexOf(item) != -1; 
    } 
    public void CopyTo(T[] array, int arrayIndex) 
    { 
     foreach (T item in this) 
      array[arrayIndex++] = item; 
    } 
    public bool IsReadOnly 
    { 
     get { return false; } 
    } 
    public bool Remove(T item) 
    { 
     int i = IndexOf(item); 
     if (i == -1) 
      return false; 
     RemoveAt(i); 
     return true; 
    } 
    System.Collections.IEnumerator 
     System.Collections.IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
    IEnumerator<T> GetEnumerator() 
    { 
     for (int i = 0; i < Count; i++) 
      yield return this[i]; 
    } 
} 

И вы использовать признак, как это:

class MyList<T> : MyBaseClass, DefaultListMethods<T> 
{ 
    public void Insert(int index, T item) { ... } 
    public void RemoveAt(int index)  { ... } 
    public T this[int index] { 
     get { ... } 
     set { ... } 
    } 
    public int Count { 
     get { ... } 
    } 
} 

Конечно, я просто царапать поверхность здесь. Более полное описание см. В документе Traits: Composable Units of Behavior (PDF).

Язык Rust (из Mozilla) реализовал Черты интересным образом: они заметили, что черты сходны с реализациями интерфейса по умолчанию, поэтому унифицированные интерфейсы и черты объединяются в одну функцию (которую они называют чертами). Основное различие между чертами и реализациями интерфейса по умолчанию (в настоящее время Java) состоит в том, что черты могут содержать частные или защищенные методы, в отличие от традиционных методов интерфейса, которые должны быть общедоступными. Если черты и интерфейсы - это , а не, объединенные в одну функцию, то другое отличие состоит в том, что вы можете иметь ссылку на интерфейс, но вы не можете иметь ссылку на признак; черта не является сама по себе.

25

Одной из проблем, связанных с множественным наследованием, является различие между наследованием интерфейсов и наследованием реализации.

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

Если вы посмотрите на C++, для каждого класса указывается после двоеточия в class декларации, вид наследования вы получаете определяется модификатором доступа (private, protected или public). С наложением public вы получаете полную беспорядочность множественного наследования — несколько интерфейсов смешиваются с несколькими реализациями. С наследованием private вы просто получаете реализацию. Объект «class Foo : private Bar» никогда не может быть передан функции, ожидающей Bar, потому что это как если бы класс Foo действительно имел только собственное поле Bar и автоматически реализованное delegation pattern.

Чистое наследование множественного наследования (которое действительно просто автоматическое делегирование) не представляет проблем и было бы замечательно иметь на C#.

Что касается множественного наследования интерфейсов от классов, существует множество различных вариантов реализации этой функции. Каждый язык с множественным наследованием имеет свои собственные правила относительно того, что происходит, когда метод вызывается с тем же именем в нескольких базовых классах. Некоторые языки, такие как Common Lisp (особенно объектная система CLOS) и Python, имеют метаобъектный протокол, где вы можете указать приоритет базового класса.

Вот одна возможность:

abstract class Gun 
{ 
    public void Shoot(object target) {} 
    public void Shoot() {} 

    public abstract void Reload(); 

    public void Cock() { Console.Write("Gun cocked."); } 
} 

class Camera 
{ 
    public void Shoot(object subject) {} 

    public virtual void Reload() {} 

    public virtual void Focus() {} 
} 

//this is great for taking pictures of targets! 
class PhotoPistol : Gun, Camera 
{ 
    public override void Reload() { Console.Write("Gun reloaded."); } 

    public override void Camera.Reload() { Console.Write("Camera reloaded."); } 

    public override void Focus() {} 
} 

var pp  = new PhotoPistol(); 
Gun gun  = pp; 
Camera camera = pp; 

pp.Shoot();     //Gun.Shoot() 
pp.Reload();     //writes "Gun reloaded" 
camera.Reload();    //writes "Camera reloaded" 
pp.Cock();      //writes "Gun cocked." 
camera.Cock();     //error: Camera.Cock() not found 
((PhotoPistol) camera).Cock(); //writes "Gun cocked." 
camera.Shoot();    //error: Camera.Shoot() not found 
((PhotoPistol) camera).Shoot();//Gun.Shoot() 
pp.Shoot(target);    //Gun.Shoot(target) 
camera.Shoot(target);   //Camera.Shoot(target) 

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

Кроме того, вы можете реализовать множественное наследование в C# сегодня с операторами неявного преобразования:

public class PhotoPistol : Gun /* ,Camera */ 
{ 
    PhotoPistolCamera camera; 

    public PhotoPistol() { 
     camera = new PhotoPistolCamera(); 
    } 

    public void Focus() { camera.Focus(); } 

    class PhotoPistolCamera : Camera 
    { 
     public override Focus() { } 
    } 

    public static Camera implicit operator(PhotoPistol p) 
    { 
     return p.camera; 
    } 
} 

Это не идеально, хотя, как это не поддерживается is и as операторов и System.Type.IsSubClassOf().

1

Нет, мы ушли от него. Вам это нужно сейчас.

1

Предпочитаю C++. Я использовал Java, C# и т. Д. По мере того, как мои программы становятся более сложными в такой среде OO, я нахожусь без множественного наследования. Это мой субъективный опыт.

Это может сделать для удивительного кода спагетти ... он может сделать для удивительно элегантного кода.

-2

Интерфейсы представляют собой множественное наследование. На самом деле, я бы рассмотрел интерфейсы Java/C# как «правильную» реализацию множественного наследования. Принуждение множественного наследования посредством использования интерфейсов, а не разрешение наследования из нескольких конкретных или абстрактных классов заставляет разработчика использовать состав/делегирование для повторного использования кода. Наследование никогда не должно использоваться для повторного использования кода, а отсутствие множества типов наследования типа C++ для разработчиков лучше разрабатываемых классов.

3

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

interface I 
{ 
    void F(); 
    void G(); 
} 


class DefaultI : I 
{ 
    void F() { ... } 
    void G() { ... } 
} 

class C : I = DefaultI 
{ 
    public void F() { ... } // implements I.F 
} 

В этом случае ((I)new C()).F() будет называть 's реализацию из I.F(), в то время как ((I)new C()).G() будет вызывать DefaultI' C реализацию х I.G().

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

2

один из по-настоящему красиво и (в то время) новые вещи о DataFlex 4GL v3 + (я знаю, я знаю, данные , что?) Была его поддержка Mixin наследования - методы от других классов могут быть повторно использованы в вашем классе; до тех пор, пока ваш класс предоставил свойства, используемые этими методами, он работал отлично, и не было проблем с «бриллиантами» или другого «наследства» с множественным наследством.

я хотел бы увидеть что-то подобное в C#, как это позволило бы упростить некоторые виды абстракции и в строительстве выдает

7

Я на самом деле пропустить множественное наследование для одной конкретной причины ... шаблона Dispose.

КАЖДЫЙ раз, когда мне нужно реализовать шаблон размещения, я говорю себе: «Мне жаль, что я не могу просто извлечь из класса, который реализует шаблон размещения с несколькими виртуальными переопределениями». Я копирую и вставляю один и тот же код котельной в каждый класс, который реализует IDispose, и я ненавижу его.

1

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

Вы решили использовать те API, которые разработчик уже написал, у вас тоже нет.

5

ДА! ДА! и да!

Серьезно, я разработке GUI библиотеки всю мою карьеру, и MI (множественное наследование) делает это гораздо проще, чем SI (Single Inheritance)

Сначала я сделал SmartWin++ в C++ (MI активно используется), то я сделал Gaia Ajax и, наконец, теперь Ra-Ajax, и я могу с предельно уверенным утверждением, что MI правил для некоторых мест. Одним из таких мест является библиотека GUI ...

И аргументы, утверждающие, что МИ «слишком сложны», и такие, как правило, используются людьми, пытающимися построить языковые войны, и попадают в лагерь, который «в настоящее время не имеет», т у МИ»...

Так же, как функциональные языки программирования (например, Lisp) учили (по„не-Lispers“) как„слишком сложные“по нефункциональным сторонникам языка программирования ...

Люди боятся неизвестного ...

MI ПРАВИЛА!

1

Дайте C# implicits, и вы не пропустите множественное наследование или любое наследование в этом отношении.

1

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

1

Я стараюсь не использовать наследование. Чем меньше я могу каждый раз.

2

Вместо множественного наследования вы можете использовать mixins, что является лучшим решением.

0

Если ввести Множественное наследование, то мы снова обращенное старую проблему алмаза C++ ...

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

Так зачем иметь множественное наследование и сделать ваш код уязвимым для неизбежных исключений ...

0

я почти не пропустите множественное наследование в C#.

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

Большинство мест, где я нахожу многократное наследование реальным значением, - это места, где он не является самим доменом, но некоторые ограничения технологии/инфраструктуры, которые требуют от вас использования ИИ. Реализация COM-объектов с использованием ATL - очень хороший пример того, где вы используете множественное наследование для реализации всех необходимых интерфейсов, которые вам нужны COM-объектам, и элегантное решение для уродливой (по сравнению с .NET) технологии. Элегантно с точки зрения, что это C++ framework!

У меня теперь есть ситуация, где я мог бы использовать множественное наследование. У меня есть один класс, который должен выводить функции из какого-либо другого объекта домена, но он также должен быть доступен для перекрестных вызовов AppDomain. Это означает, что он ДОЛЖЕН наследовать от MarshalByRefObject. Поэтому в данном конкретном случае мне бы хотелось получить как от MarshalByRefObject, так и от моего конкретного объекта домена. Это невозможно, поэтому мой класс должен реализовать тот же интерфейс, что и мой объект домена, и переадресовывать вызовы в агрегированный экземпляр.

Но это, как я уже сказал, случай, когда технология/структура помещает ограничение, а не сама модель домена.

0

Я говорю «нет» до «Проблема с алмазами» (большая причина, почему множественное наследование с классами плохо) решается должным образом, и если решение так же хорошо, как и с использованием интерфейсов. В двух словах проблема Diamond в основном связана с потенциальной неоднозначностью данных, методов и событий в классах из-за множественного наследования через классы.

P/S Вы «редко» избегаете программного решения, которое вам очень нужно, потому что это сложно. «Трудность» не является оправданием того, что у вас нет множественного наследства. Многопоточность жесткая, но она доступна на C#. Большой недостаток, который не имеет множественного наследования, связан с проблемой алмаза (http://en.wikipedia.org/wiki/Diamond_problem). Применительно к вашим комментариям о лучших альтернативах применимы смешные рассуждения (люди решают и думают по-разному, поэтому иногда одно решение - плохая идея), и подходящие варианты уже существуют (зачем создавать LINQ, когда ADO.NET делает трюк и является зрелым ... должным образом до прочности одного над другим.)

1

Нет, если проблема с алмазом не решена. и вы можете использовать композицию, пока это не будет разрешено.

0

Это упростит работу, сократит количество кода, если интерфейсы могут быть реализованы. Но могли ли они быть пропущены - использовались больше, чем использовались должным образом? Я думаю, что пока вы не увидите, как это можно сделать правильно, вы не пропустите это. Меня раздражает аргумент о том, что множественное наследование небезопасно. Это не. Но почти все языковые реализации. Но нам это нужно? Я не знаю.

Я бы предпочел ковариацию возвращаемого типа, это может быть легко добавлено (просто расслабьтесь в правилах, на возвращаемом типе на over-ridden) и всегда в безопасности.

пример:

class shape {} 

class circle : shape {} 

interface part { 
    shape Form(); 
} 

interface wheel : part { 
    circle Form(); 
} 
Смежные вопросы