.NET中的多重继承有哪些好的替代方案?

Gif*_*guy 36 .net c# inheritance multiple-inheritance .net-3.5

在WPF应用程序中,我的类层次结构遇到了一些问题.这是将两个继承树合并在一起的问题之一,如果没有多重继承,就无法找到任何合理的方法来使继承顺利运行.我想知道是否有人有任何明智的想法让这种系统工作,而不会让它无法遵循或调试.

我是一名低级工程师,所以我的第一个想法总是,"哦!我只是用原生C++写一些这些类,并在外部引用它们!然后我可以让我所有的老派OO好玩!" 唉,当你需要从托管控件继承时,这没有用...

请允许我显示当前投影类图的片段:

 ____________________________________      _____________________________________
| CustomizableObject                 |    | System.Windows.Controls.UserControl |
|____________________________________|    |_____________________________________|
|   string XAMLHeader()              |                        ?
|   string XAMLFooter()              |?--?                    |
|   CustomizableObject LoadObject()  |   \                    |
|   <Possible other implementations> |    \                   |
|____________________________________|     \                  |
         ?                      ?           \                 |
         |                      |            \                |
         |                      |             \               |
 _________________    ______________________   \    _____________________
| SpriteAnimation |  | SpriteAnimationFrame |  ?---| CustomizableControl |
|_________________|  |______________________|      |_____________________|
                                                      ?             ?
                                                      |             |
                                                      |             |
                                                  ________    _____________
                                                 | Sprite |  | SpriteFrame |
                                                 |________|  |_____________|
Run Code Online (Sandbox Code Playgroud)

问题非常明确:CustomizableObject和CustomizableControl对象树的分离---以及将UserControl插入树中的一个而不是两个中.

将CustomizableObject的实现移动到其派生类中没有任何实际意义,因为实现不会因类而异.此外,多次实施它会非常困惑.所以我真的不想让CustomizableObject成为一个接口.界面解决方案对我没有任何意义.(说实话,接口从来没有真正对我有意义......)

所以我再说一遍,有人有什么好主意吗?这是一个真正的泡菜.我想了解更多关于使接口与我的对象树一起工作的信息,而不是反对它.我正在使用WPF和C#制作这个简单的精灵引擎作为一个可靠的练习,比什么都重要.这在C++中很容易解决 - 但是我需要弄清楚如何在托管环境中解决这些问题,而不是每当事情变得艰难时就把手放在空中并回到Win32.

Ed *_* S. 29

你有两个选择; 使用接口,或使用组合.老实说,接口非常强大,并且在阅读完这一行之后

界面解决方案对我没有任何意义.(说实话,接口从来没有真正对我有意义......)

我认为你应该学习如何正确使用它们.也就是说,如果只有一些逻辑表明多个类需要,但是这些类从同一个基类继承是没有意义的,只需创建一个类来封装该逻辑并将该类的成员变量添加到您的类中这给你带来了麻烦.这样,所有类都包含逻辑,但在它们的继承层次结构中可以是独立的.如果类应该实现公共接口,那么使用接口.


dah*_*byk 17

一种方法是使用带有接口的扩展方法来提供"派生类"实现,就像System.Linq.Queryable一样:

interface ICustomizableObject
{
    string SomeProperty { get; }
}

public static class CustomizableObject
{
    public static string GetXamlHeader(this ICustomizableObject obj)
    {
        return DoSomethingWith(obj.SomeProperty);
    }

    // etc
}

public class CustomizableControl : System.Windows.Controls.UserControl, ICustomizableObject
{
    public string SomeProperty { get { return "Whatever"; } }
}
Run Code Online (Sandbox Code Playgroud)

用法:只要您具有定义扩展方法的命名空间(或与命名空间相同)的using指令:

var cc = new CustomizableControl();
var header = cc.GetXamlHeader();
Run Code Online (Sandbox Code Playgroud)

  • 另外,请查看MSDN上的这篇文章:http://msdn.microsoft.com/en-us/vcsharp/bb625996.aspx (4认同)
  • 只是为了在游行中稍微下雨,与完全MI相比,这有一些不足,因为它可能在.NET中.首先,您不能在不破坏二进制兼容性的情况下发展接口(对于具有小型用户社区的库而言通常不是问题).这可以在CLR的某个未来版本中修复,其中它们可以允许接口方法具有默认实现.其次,在MI中,多个基类中的每一个都可以向组合类添加数据字段.您必须使用某种线程局部静态字典混乱来通过扩展方法来模拟它. (4认同)
  • 一些好点.如果您需要接口未提供的共享状态,扩展方法确实会中断,因此请提前计划!有关接口的默认实现(以及更多)的更多信息,请查看第9频道的视频:专家专家:Erik Meijer和Anders Hejlsberg - C的未来#http://channel9.msdn.com/shows/Going+Deep/专家对专家的Anders-Hejlsberg最面向未来的的-C / (2认同)

Joe*_*orn 7

我正在看这个,CustomizableObject只是尖叫成一个接口(因为每个具体的类型都可以转换为对象,这部分名称是多余的).您遇到的问题是您不确定如何保留一些将被共享的基本逻辑或仅因实现而略有不同,并且您希望将此逻辑存储在树本身中以便它将以多态方式工作(是一个字?).

您可以通过代表实现这一目标.我不确定哪些成员给你带来了麻烦,但也许更像这样的东西:

 ____________________________________      _____________________________________
| ICustomizable                      |    | System.Windows.Controls.UserControl |
|                                    |    |_____________________________________|
|   Func<string> XAMLHeader;         |                        ?
|   Func<string> XAMLFooter          |?--?                    |
|   ICustomizabl LoadObject() |   \                    |
|   <Possible other implementations> |    \                   |
|____________________________________|     \                  |
         ?                      ?           \                 |
         |                      |            \                |
         |                      |             \               |
 _________________    ______________________   \    _____________________
| SpriteAnimation |  | SpriteAnimationFrame |  ?---| CustomizableControl |
|_________________|  |______________________|      |_____________________|
                                                      ?             ?
                                                      |             |
                                                      |             |
                                                  ________    _____________
                                                 | Sprite |  | SpriteFrame |
                                                 |________|  |_____________|
Run Code Online (Sandbox Code Playgroud)

此外,您可能有一些真正静态的逻辑,您认为它们确实属于您的CustomizableObject类型.但这可能是错误的:您构建了类型,意图在特定情况下使用该类型.例如,从上下文看起来您将创建这些控件和动画并在Windows窗体上使用它们.要做的是拥有自己的表单,继承自System.Windows.Form基础,这个新的表单类型应该知道ICustomizableObject以及如何使用它.这就是静态逻辑的用武之地.

这似乎有点尴尬,但当您决定更改演示引擎时,它已被证明是准确的.如果将此代码移植到WPF或Silverlight会发生什么?他们可能需要使用您的实现代码,而不是Windows Forms,您仍然可能需要更改CustomizableControl实现.但是你的静态逻辑现在都在正确的位置.

最后,你使用的LoadObject()方法在我错误的地方也很突出.你说你希望每个Customizable类型都提供一个你可以调用的方法,它知道如何加载/构建自己.但这确实是不同的.您可能需要另一个名为的接口IConstructable<T>,并且您的ICustomizable类型实现了(IConstructable<ICustomizable>).