C# 试图继承三个基类,不能

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2201058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 00:20:18  来源:igfitidea点击:

Trying to inherit three base classes and can't

c#inheritancemultiple-inheritance

提问by Peter

I have a few questions related to the design of my Userclass but they are different enough that I think they should be independent questions.

我有一些与我的User课程设计相关的问题,但它们足够不同,我认为它们应该是独立的问题。

So, the first is related to inheritance of base classes. I am currently inheriting two classes, ProfileBaseand ISessionMgrEntryas such:

因此,第一个与基类的继承有关。我目前继承两个类,ProfileBaseISessionMgrEntry为这样的:

public class User : ProfileBase, ISessionMgrEntry

But, I also want to inherit a third class, MembershipUser, like this:

但是,我也想继承第三个类MembershipUser,像这样:

public class User : ProfileBase, MembershipUser, ISessionMgrEntry

However, the compiler won't let me do that. Why? And, how do I get around this?

但是,编译器不会让我这样做。为什么?而且,我该如何解决这个问题?

Thanks.

谢谢。

PS - ASP.NET 3.5 / C#

PS - ASP.NET 3.5 / C#

EDIT

编辑

Hi. I think the below solution may work for what I am trying to acheive. It seems pretty simple and straight forward. I am doing this so I can create a complete/combined Userobject. Does anybody see any reason why this might cause problems? One that came up while I was ding this is overlapping properties. For example, both MembershipUserand ProfileBaseshare "UserName". Should I just chose one or the other or will this be a design flaw? Suggestions? Thanks again.

你好。我认为以下解决方案可能适用于我想要实现的目标。这看起来非常简单和直接。我这样做是为了创建一个完整/组合的User对象。有没有人看到这可能会导致问题的任何原因?在我进行此操作时出现的一个是重叠属性。例如,无论是MembershipUserProfileBase共享“ 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; }
        } 

        ....

   }

采纳答案by ChrisF

In the first example you're not actually inheriting from two classes, but from one class and an interface.

在第一个示例中,您实际上不是从两个类继承,而是从一个类和一个接口继承。

C# doesn't allow multiple inheritance from classes, but does allow you to implement multiple interfaces. See this MSDN blog post(link is dead so text is pasted below) for more information on why.

C# 不允许类的多重继承,但允许您实现多个接口。看这篇 MSDN 博客文章(链接已死,因此文本粘贴在下面)以获取有关原因的更多信息。

You will have to make an IMembershipUserinterface and implement that in your Userclass.

您必须创建一个IMembershipUser接口并在您的User类中实现它。

Interfaces are usually given names based on the concrete class name prefixed by an I. So the class MembershipUserwould have an interface IMembershipUser. There's nothing stopping you using some other name, but everyone who uses interfaces is used to this naming convention.

接口通常根据以I.为前缀的具体类名命名。所以这个类MembershipUser会有一个 interface IMembershipUser。没有什么可以阻止您使用其他名称,但是每个使用接口的人都习惯于这种命名约定。

There are a number of reasons we don't implement Multiple Implementation Inheritance directly. (As you know, we support Multiple Interface Inheritance).

However, I should point out that it's possible for compilers to create MI for their types inside the CLR. There are a few rough edges if you go down this path: the result is unverifiable, there is no interop with other languages via the CLS, and in V1 and V1.1 you may run into deadlocks with the OS loader lock. (We're fixing that last problem, but the first two problems remain). The technique is to generate some VTables in RVA-based static fields. In order to deposit the addresses of managed methods (which probably haven't been JITted yet), you use the VTFixup construct. This construct is a table of triplets. The triplets consist of a token to a managed method, an address in your image that should be fixed up (in this case, a slot of the VTable you are creating in the RVA-based static), and some flags. The possible flags are described in corhdr.h and they allow you to specify 32- vs. 64-bit pointer sizes, control over virtual behavior, and whether some reverse-PInvoke behavior should be applied in the form of a thunk that eventually dispatches to the managed method. If we are performing an unmanaged->managed transition, you also have some control over which AppDomain should be selected for us to dispatch the call. However, one of these options (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) doesn't exist in V1. We added it in V1.1.

There are several reasons we haven't provided a baked-in, verifiable, CLS-compliant version of multiple implementation inheritance:

  1. Different languages actually have different expectations for how MI works. For example, how conflicts are resolved and whether duplicate bases are merged or redundant. Before we can implement MI in the CLR, we have to do a survey of all the languages, figure out the common concepts, and decide how to express them in a language-neutral manner. We would also have to decide whether MI belongs in the CLS and what this would mean for languages that don't want this concept (presumably VB.NET, for example). Of course, that's the business we are in as a common language runtime, but we haven't got around to doing it for MI yet.

  2. The number of places where MI is truly appropriate is actually quite small. In many cases, multiple interface inheritance can get the job done instead. In other cases, you may be able to use encapsulation and delegation. If we were to add a slightly different construct, like mixins, would that actually be more powerful?

  3. Multiple implementation inheritance injects a lot of complexity into the implementation. This complexity impacts casting, layout, dispatch, field access, serialization, identity comparisons, verifiability, reflection, generics, and probably lots of other places.

It's not at all clear that this feature would pay for itself. It's something we are often asked about. It's something we haven't done due diligence on. But my gut tells me that, after we've done a deep examination, we'll still decide to leave the feature unimplemented.

我们不直接实现多重实现继承的原因有很多。(如您所知,我们支持多接口继承)。

但是,我应该指出,编译器可以在 CLR 中为它们的类型创建 MI。如果沿着这条路走下去,会有一些困难:结果无法验证,没有通过 CLS 与其他语言的互操作,并且在 V1 和 V1.1 中,您可能会遇到 OS 加载程序锁的死锁。(我们正在解决最后一个问题,但前两个问题仍然存在)。该技术是在基于 RVA 的静态字段中生成一些 VTable。为了存放托管方法的地址(可能还没有经过 JIT 处理),您可以使用 VTFixup 构造。这个结构是一个三元组表。三元组由托管方法的令牌、图像中应该修复的地址(在这种情况下,是您在基于 RVA 的静态中创建的 VTable 的插槽)和一些标志组成。corhdr.h 中描述了可能的标志,它们允许您指定 32 位与 64 位指针大小、控制虚拟行为,以及是否应以最终分派到 thunk 的形式应用某些反向 PInvoke 行为管理的方法。如果我们正在执行非托管-> 托管转换,您还可以控制应为我们选择哪个 AppDomain 来调度调用。但是,这些选项之一 (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) 在 V1 中不存在。我们在 V1.1 中添加了它。如果我们正在执行非托管-> 托管转换,您还可以控制应为我们选择哪个 AppDomain 来调度调用。但是,这些选项之一 (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) 在 V1 中不存在。我们在 V1.1 中添加了它。如果我们正在执行非托管-> 托管转换,您还可以控制应为我们选择哪个 AppDomain 来调度调用。但是,这些选项之一 (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) 在 V1 中不存在。我们在 V1.1 中添加了它。

我们没有提供内置的、可验证的、符合 CLS 的多重实现继承版本有几个原因:

  1. 不同的语言实际上对 MI 的工作方式有不同的期望。例如,如何解决冲突以及重复的碱基是合并还是冗余。在我们可以在 CLR 中实现 MI 之前,我们必须对所有语言进行调查,找出共同的概念,并决定如何以一种语言中立的方式来表达它们。我们还必须决定 MI 是否属于 CLS 以及这对于不需要这个概念的语言(例如可能是 VB.NET)意味着什么。当然,这就是我们作为公共语言运行时所从事的业务,但我们还没有为 MI 做这件事。

  2. 真正适合 MI 的地方其实很少。在许多情况下,多接口继承可以代替完成工作。在其他情况下,您也许可以使用封装和委托。如果我们添加一个稍微不同的结构,比如 mixin,那实际上会更强大吗?

  3. 多实现继承给实现注入了很多复杂性。这种复杂性会影响转换、布局、分派、字段访问、序列化、身份比较、可验证性、反射、泛型以及可能很多其他地方。

目前尚不清楚此功能是否会为自己付出代价。这是我们经常被问到的问题。这是我们没有做尽职调查的事情。但我的直觉告诉我,在我们进行深入研究之后,我们仍会决定不实施该功能。

回答by Oded

C# doesn't support multiple inheritance.

C# 不支持多重继承。

In the first example you are inheriting from ProfileBaseand declaring your class to be implementing the ISessionMgrEntryinterface.

在第一个示例中,您继承ProfileBase并声明您的类要实现该ISessionMgrEntry接口。

You can add as many interfaces to a class as you want (provided you implement them all).

您可以根据需要向类添加任意数量的接口(前提是您实现了所有接口)。

回答by Jamie Ide

C# only supports single inheritance. You can either chain together your classes (i.e. MembershipUserinherits from ProfileBase) or use interfaces.

C# 只支持单继承。您可以将您的类链接在一起(即MembershipUser继承自ProfileBase)或使用interfaces.

回答by nWorx

in c# you just can inherit from one class, but implement as many interfacesas you want. in your case ProfileBaseand MembershipUserare classes and ISessionMgrEntryis an interface.

在 c# 中,您只能从一个类继承,但可以根据需要实现任意数量的接口。在您的情况下,ProfileBase并且MembershipUser是类并且ISessionMgrEntry是接口。

回答by BlueRaja - Danny Pflughoeft

C# does not allow multiple inheritance.

C# 不允许多重继承

回答by Jeff Hornby

C# only allows single inheritance: you can only inherit from one base class. In the first case ISessionMgrEntryis an interface which is different from a base class. Here's a good article on the difference: http://msdn.microsoft.com/en-us/library/ms973861.aspx

C#只允许单继承:你只能从一个基类继承。在第一种情况下ISessionMgrEntry是一个不同于基类的接口。这是一篇关于差异的好文章:http: //msdn.microsoft.com/en-us/library/ms973861.aspx

In the second case you are trying to inherit from both ProfileBaseand MembershipUser, which the compiler won't allow. The best way to get around this would be to encapsulate one (or both) of ProfileBaseand MembershipUser.

在第二种情况下,您试图从ProfileBaseand继承MembershipUser,这是编译器不允许的。要解决这个问题的最好办法是封装的一个(或两个)ProfileBaseMembershipUser

回答by jonp

Multiple interfaces with identical member names are not a problem. If the members can share the same implementation, just create a public member with the same name; if they can't share the same implementation, you can just explicitly implement one (or all) of the members.

具有相同成员名称的多个接口不是问题。如果成员可以共享相同的实现,只需创建一个同名的公共成员;如果它们不能共享相同的实现,您可以明确地实现一个(或所有)成员。

For example, IEnumerable<T>inherits IEnumerable, and both provide a GetEnumerator()method with differing return types. Consequently, IEnumerable.GetEnumerator()is generally explicitly implemented:

例如,IEnumerable<T>inheritsIEnumerable和两者都提供GetEnumerator()具有不同返回类型的方法。因此,IEnumerable.GetEnumerator()通常明确实施:

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

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

Calling GetEnumerator()in IEnumerable.GetEnumerator()isn't an infinitely recursive call; it calls the public member of the same name, notitself (i.e. the IEnumerable.GetEnumerator()method).

调用GetEnumerator()IEnumerable.GetEnumerator()是不是一个无限递归调用; 它调用同名的公共成员,而不是它本身(即IEnumerable.GetEnumerator()方法)。