Множественное наследование не поддерживается 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) состоит в том, что черты могут содержать частные или защищенные методы, в отличие от традиционных методов интерфейса, которые должны быть общедоступными. Если черты и интерфейсы - это , а не, объединенные в одну функцию, то другое отличие состоит в том, что вы можете иметь ссылку на интерфейс, но вы не можете иметь ссылку на признак; черта не является сама по себе.
Я свежий Outta голосов, так считают это +1 – Rob 2008-10-10 14:51:38
Ну, вы всегда можете вернуться через несколько часов ;-p – 2008-10-10 14:52:28
Я слышал подобные аргументы от разработчиков, которые исходят из процедурного фона программирования. Их аргумент был бы «объектами, которые никогда не нуждались в них». Это не так. Если они более выразительны, они имеют ценность (в правильной ситуации). – 2008-10-10 14:58:38