Попытка наследовать три базовых класса и не может - PullRequest
24 голосов
/ 04 февраля 2010

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

Итак, первое связано с наследованием базовых классов. Я сейчас наследуя два класса, ProfileBase и ISessionMgrEntry как таковые:

public class User : ProfileBase, ISessionMgrEntry

Но я также хочу унаследовать третий класс, MembershipUser, например:

public class User : ProfileBase, MembershipUser, ISessionMgrEntry

Однако компилятор не позволит мне сделать это. Зачем? И как я могу получить вокруг этого?

Спасибо.

PS - ASP.NET 3.5 / C #

EDIT

Привет. Я думаю, что приведенное ниже решение может работать для того, что я пытаюсь достичь. Это кажется довольно простым и понятным. Я делаю это, чтобы я мог создать полный / комбинированный User объект. Кто-нибудь видит какую-либо причину, почему это может вызвать проблемы? Тот, который появился, когда я был в дин, это перекрывающиеся свойства. Например, и MembershipUser, и ProfileBase совместно используют "UserName". Должен ли я просто выбрать один или другой, или это будет недостаток дизайна? Предложения? Еще раз спасибо.

 public class User
    {

        #region Constructors
            private readonly MembershipUser _MembershipUser;
            private readonly ProfileBase _ProfileBase;
        #endregion

        public User()
        {
            _MembershipUser = new MembershipUser();
            _ProfileBase = new ProfileBase();

        }

        public string Comment
        {
            get { return _MembershipUser.Comment as string; }
            set { _MembershipUser.Comment = value; }
        }

        public bool IsAnonymous
        {
            get { return _ProfileBase.IsAnonymous as bool; }
        } 

        ....

   }

Ответы [ 7 ]

38 голосов
/ 04 февраля 2010

В первом примере вы на самом деле наследуете не от двух классов, а от одного класса и интерфейса.

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

Вам нужно будет создать интерфейс IMembershipUser и реализовать его в своем классе User.

Интерфейсам обычно присваиваются имена на основе конкретного имени класса с префиксом I. Таким образом, класс MembershipUser будет иметь интерфейс IMembershipUser. Ничто не мешает вам использовать какое-то другое имя, но каждый, кто использует интерфейсы, привык к этому соглашению об именах.

Есть ряд причин, по которым мы не реализуем Наследование реализации напрямую. (Как вы знаете, мы поддерживаем несколько Наследование интерфейса).

Однако я должен отметить, что компиляторы могут создавать MI для их типов внутри CLR. Есть несколько грубых краев, если вы идти по этому пути: результат не поддается проверке, нет взаимодействия с другими языками через CLS, а в V1 и V1.1 вы можете столкнуться с взаимоблокировки с блокировкой загрузчика ОС. (Мы исправляем эту последнюю проблему, но первые две проблемы остаются). Техника состоит в том, чтобы генерировать некоторые VTables в статических полях на основе RVA. Для того, чтобы внести адреса управляемых методов (которые, вероятно, еще не были JITted), вы используете конструкция VTFixup. Эта конструкция представляет собой таблицу триплетов. триплеты состоят из токена для управляемого метода, адрес в вашем изображение, которое должно быть исправлено (в этом случае слот VTable вы создаем в RVA на основе статики) и некоторые флаги. Возможный флаги описаны в corhdr.h, и они позволяют вам указать 32- против Размеры 64-битных указателей, контроль над виртуальным поведением и Обратное PInvoke поведение должно быть применено в форме thunk, который в конце концов отправляет управляемый метод. Если мы выполняем неуправляемый-> управляемый переход, у вас также есть некоторый контроль над которым AppDomain должен быть выбран для нас, чтобы отправить вызов. Тем не менее, один из этих параметров (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) нет существуют в V1. Мы добавили его в V1.1.

Есть несколько причин, по которым мы не предоставили запеченный, проверяемый, CLS-совместимая версия наследования нескольких реализаций:

  1. Различные языки на самом деле имеют разные ожидания относительно того, как работает MI. Например, как разрешаются конфликты и дублируются ли базы объединены или избыточны. Прежде чем мы сможем реализовать MI в CLR, мы должны сделать обзор всех языков, выяснить общее концепции, и решить, как выразить их нейтральным языком. Мы также должны были бы решить, принадлежит ли MI в CLS и что это будет означать для языков, которые не хотят эту концепцию (предположительно VB.NET, например). Конечно, это бизнес, в котором мы находимся как общеязыковая среда выполнения, но мы не удосужились сделать это для MI еще.

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

  3. Множественное наследование реализации вносит большую сложность в реализацию. Эта сложность влияет на кастинг, макет, диспетчеризация, доступ к полям, сериализация, сравнение идентификаторов, проверяемость, рефлексия, дженерики и, возможно, множество других места.

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

6 голосов
/ 04 февраля 2010

в c # вы можете наследовать от одного класса , но реализовывать столько интерфейсов , сколько захотите. в вашем случае ProfileBase и MembershipUser являются классами, а ISessionMgrEntry является интерфейсом.

4 голосов
/ 04 февраля 2010
4 голосов
/ 04 февраля 2010

C # поддерживает только одиночное наследование. Вы можете объединить ваши классы в цепочку (то есть MembershipUser наследует от ProfileBase) или использовать interfaces.

2 голосов
/ 04 февраля 2010

C # допускает только одно наследование: вы можете наследовать только от одного базового класса. В первом случае ISessionMgrEntry - это интерфейс, который отличается от базового класса. Вот хорошая статья о разнице: http://msdn.microsoft.com/en-us/library/ms973861.aspx

Во втором случае вы пытаетесь унаследовать от ProfileBase и MembershipUser, что компилятор не допустит. Лучший способ обойти это - заключить в капсулу один (или оба) из ProfileBase и MembershipUser.

2 голосов
/ 04 февраля 2010

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

В первом примере вы наследуете от ProfileBase и объявляете свой класс для реализации интерфейса ISessionMgrEntry.

Вы можете добавить столько классов в класс, сколько пожелаете (при условии, что вы реализуете их все).

0 голосов
/ 05 февраля 2010

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

Например, IEnumerable<T> наследует IEnumerable, и оба предоставляют метод GetEnumerator() с различными типами возврата. Следовательно, IEnumerable.GetEnumerator() обычно явно реализовано:

class Foo : IEnumerable<object>{
    // explicitly implement IEnumerable.GetEnumerator()
    IEnumerator IEnumerable.GetEnumerator ()
    {
        return GetEnumerator();
    }

    public IEnumerator<object> GetEnumerator ()
    {
        yield break;
    }
}

Вызов GetEnumerator() в IEnumerable.GetEnumerator() не является бесконечно рекурсивным вызовом; он вызывает открытый элемент с таким же именем, , а не сам (то есть метод IEnumerable.GetEnumerator()).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...