Ответ 1
В первом примере вы на самом деле наследуете не от двух классов, а от одного класса и интерфейса.
С# не допускает множественного наследования от классов, но позволяет реализовать несколько интерфейсов. См. Это сообщение в блоге MSDN (ссылка неактивна, поэтому текст вставлен ниже) для получения дополнительной информации о причинах.
Вам нужно будет создать интерфейс IMembershipUser
и реализовать его в своем классе User
.
Интерфейсам обычно дают имена на основе конкретного имени класса с префиксом I
Так что класс MembershipUser
будет иметь интерфейс IMembershipUser
. Ничто не мешает вам использовать какое-то другое имя, но каждый, кто использует интерфейсы, привык к этому соглашению об именах.
Есть ряд причин, по которым мы не реализуем множественное наследование реализации напрямую. (Как вы знаете, мы поддерживаем множественное наследование интерфейса).
Однако я должен отметить, что компиляторы могут создавать MI для своих типов внутри CLR. Если идти по этому пути, есть несколько грубых моментов: результат не поддается проверке, нет взаимодействия с другими языками через CLS, а в V1 и V1.1 вы можете столкнуться с тупиками с блокировкой загрузчика ОС. (Мы исправили эту последнюю проблему, но первые две проблемы остались). Метод заключается в создании некоторых VTable-таблиц в статических полях на основе RVA. Для размещения адресов управляемых методов (которые, вероятно, еще не были JITted), вы используете конструкцию VTFixup. Эта конструкция представляет собой таблицу триплетов. Триплеты состоят из токена для управляемого метода, адреса в вашем образе, который должен быть исправлен (в данном случае, слота VTable, который вы создаете в статической RVA-основе), и некоторых флагов. Возможные флаги описаны в corhdr.h, и они позволяют вам указать 32- в сравнении с размерами 64-битных указателей, управлять виртуальным поведением, а также следует ли применять какое-либо поведение reverse-PInvoke в виде thunk, который в конечном итоге отправляет к управляемому методу. Если мы выполняем управляемый переход unmanaged->, у вас также есть некоторый контроль над тем, какой AppDomain должен быть выбран для нас для отправки вызова. Однако один из этих вариантов (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) не существует в V1. Мы добавили его в V1.1.
Есть несколько причин, по которым мы не предоставили встроенную, проверяемую CLS-совместимую версию наследования нескольких реализаций:
У разных языков разные ожидания относительно того, как работает MI. Например, как разрешаются конфликты и объединяются или дублируются дублирующие базы. Прежде чем мы сможем внедрить MI в CLR, мы должны сделать обзор всех языков, выяснить общие понятия и решить, как выразить их нейтральным языком. Мы также должны были бы решить, принадлежит ли MI в CLS и что это будет означать для языков, которые не хотят этого понятия (например, VB.NET, например). Конечно, это бизнес, в котором мы находимся как общеязыковая среда исполнения, но мы пока не успели сделать это для MI.
Количество мест, где MI действительно подходит, на самом деле довольно мало. Во многих случаях множественное наследование интерфейса может сделать работу вместо этого. В других случаях вы можете использовать инкапсуляцию и делегирование. Если бы мы добавили немного другую конструкцию, такую как mixins, это было бы на самом деле более мощным?
Наследование множественных реализаций вносит много сложностей в реализацию. Эта сложность влияет на приведение, компоновку, диспетчеризацию, доступ к полям, сериализацию, сравнение идентификаторов, проверяемость, рефлексию, обобщение и, возможно, множество других мест.
Совершенно не ясно, что эта функция окупится. Это то, о чем нас часто спрашивают. Это то, что мы не сделали должной осмотрительности. Но моя интуиция подсказывает мне, что после того, как мы сделали глубокое исследование, мы все же решили оставить эту функцию невыполненной.