У меня есть несколько вопросов, связанных с дизайном моего User
класс, но они достаточно отличаются, что я думаю, что они должны быть независимыми вопросами.
Так, первое связано с наследованием базовых классов. Я в настоящее время наследовал два класса, ProfileBase
и ISessionMgrEntry
как таковой:
public class User : ProfileBase, ISessionMgrEntry
Но, я также хочу наследовать третий класс, MembershipUser
, как это:
public class User : ProfileBase, MembershipUser, ISessionMgrEntry
Однако компилятор не позволит мне сделать это. Почему? И, как я обхожу это?
Спасибо.
PS - ASP.NET 3.5 / C#
Править
Привет. Я думаю ниже решения, может работать на то, чего я пытаюсь достигнуть. Это кажется довольно простым и прямым. Я делаю это так, я могу создать полное/объединенное 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; }
}
....
}
В первом примере вы фактически наследуете не два класса, а один класс и интерфейс.
C # не допускает множественного наследования от классов, но позволяет реализовать несколько интерфейсов. См. это сообщение в блоге MSDN (ссылка мертва, поэтому текст вставлен ниже) для получения дополнительной информации о том, почему.
Вам нужно будет создать интерфейс IMembershipUser
и реализовать его в своем классе User
.
Интерфейсы обычно получают имена на основе имени конкретного класса с префиксом I
. Таким образом, класс MembershipUser
будет иметь интерфейс IMembershipUser
. Ничто не мешает вам использовать какое-то другое имя, но все, кто использует интерфейсы, привыкли к этому соглашению об именах.
Есть ряд причин, по которым мы не реализуем множественное наследование реализации напрямую. (Как вы знаете, мы поддерживаем множественное наследование интерфейсов ).
Однако я должен отметить, что компиляторы могут создавать MI для своих типов внутри CLR.Если вы пойдете по этому пути, есть несколько острых углов: результат не поддается проверке, нет взаимодействия с другими языками через CLS, а в V1 и V1.1 вы можете столкнуться с тупиковых ситуаций с блокировкой загрузчика ОС. (Мы решаем эту последнюю проблему, , но первые две проблемы остаются). Метод состоит в том, чтобы сгенерировать несколько таблиц VT в статических полях на основе RVA. Чтобы разместить адреса управляемых методов (которые, вероятно, еще не были JITted), вы используете конструкцию VTFixup. Эта конструкция представляет собой таблицу троек. Тройки состоят из токена управляемого метода, адреса в вашем изображении , который необходимо исправить (в данном случае, слот таблицы VTable, которую вы создаете в статика на основе RVA) и некоторые флаги. Возможные флаги описаны в corhdr.h, и они позволяют вам указать 32-битные или 64-битные размеры указателя, контроль над виртуальным поведением, а также то, будут ли некоторые обратные Поведение PInvoke следует применять в форме преобразователя, который в конечном итоге отправляет управляемому методу. Если мы выполняем переход неуправляемый-> управляемый, у вас также есть некоторый контроль над тем, какой домен приложения должен быть выбран для отправки вызова. Однако один из этих параметров (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) не существует в V1. Мы добавили его в V1.1.
Есть несколько причин, по которым мы не предоставили встроенную, поддающуюся проверке, CLS-совместимую версию множественного наследования реализации:
На самом деле разные языки имеют разные ожидания относительно того, как работает MI. Например, как разрешаются конфликты и объединяются или дублируются повторяющиеся базы.Прежде чем мы сможем реализовать MI в CLR, мы должны провести обзор всех языков, выяснить общие концепции и решить, как выразить их в нейтральной для языка манере. { {1}} Нам также нужно будет решить, принадлежит ли MI к CLS и что это будет означать для языков, которым не нужна эта концепция (например, VB.NET). Конечно, мы занимаемся этим как общеязыковая среда выполнения, но у нас еще не было времени сделать это для MI .
Количество мест, где действительно подходит ИМ, на самом деле довольно мало. Во многих случаях вместо этого можно выполнить задание с помощью множественного наследования интерфейсов. В других случаях вы можете использовать инкапсуляцию и делегирование. Если бы мы добавили немного другую конструкцию, например миксины , было бы это на самом деле более мощным?
Множественное наследование реализаций привносит много сложности в реализацию. Эта сложность влияет на приведение типов, разметку, отправку, доступ к полям, сериализацию, сравнение идентичности, проверяемость, отражение, обобщения и, возможно, многие другие места.
Непонятно, окупится ли эта функция сама за себя. Это то, о чем нас часто спрашивают. Это то, что мы не сделали должной осмотрительности. Но моя интуиция подсказывает мне, что после тщательного исследования мы все же решим оставить эту функцию нереализованной.
в C # вы просто можете наследовать от одного класса , но реализует столько интерфейсов , сколько хотите. { {1}} в вашем случае ProfileBase
и MembershipUser
- это классы, а ISessionMgrEntry
- интерфейс.
C# позволяет наследовать только одно: можно наследовать только от одного базового класса. В первом случае ISessionMgrEntry
представляет собой интерфейс, отличный от базового класса. Вот хорошая статья об этой разнице: http://msdn.microsoft.com/en-us/library/ms973861.aspx
Во втором случае вы пытаетесь наследовать от обоих ProfileBase
и MembershipUser
, что компилятор не позволит. Лучший способ обойти это - инкапсулировать один (или оба) из ProfileBase
и MembershipUser
.
C # поддерживает только одиночное наследование. Вы можете объединить свои классы в цепочку (т.е. MembershipUser
наследуется от ProfileBase
) или использовать интерфейсы
.
C # не поддерживает множественное наследование.
В первом примере вы наследуете от ProfileBase
и объявляете, что ваш класс реализует интерфейс ISessionMgrEntry
.
Вы можете добавить к классу столько интерфейсов, сколько захотите (при условии, что вы их все реализуете).
Несколько интерфейсов с одинаковыми именами элементов не являются проблемой. Если члены могут использовать одну и ту же реализацию, просто создайте публичный член с тем же именем; если они не могут использовать одну и ту же реализацию, вы можете просто явно реализовать один (или все) члены.
Например, IEnumerable
наследует 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 ()
).