Подтвердить что ты не робот

Попытка наследовать три базовых класса и не может

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

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

public class User : ProfileBase, ISessionMgrEntry

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

public class User : ProfileBase, MembershipUser, ISessionMgrEntry

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

Спасибо.

PS - ASP.NET 3.5/С#

ИЗМЕНИТЬ

Привет. Я думаю, что решение ниже может работать для того, что я пытаюсь добиться. Это кажется довольно простым и прямым. Я делаю это, чтобы создать полный/комбинированный объект 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; }
        } 

        ....

   }
4b9b3361

Ответ 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-совместимую версию наследования нескольких реализаций:

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

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

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

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

Ответ 2

в С# вы можете просто наследовать один класс, но реализовать столько интерфейсов, сколько хотите. в вашем случае ProfileBase и MembershipUser - классы, а ISessionMgrEntry - это интерфейс.

Ответ 3

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

Ответ 5

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

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

Ответ 6

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

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

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

Ответ 7

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

Например, 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()).