C# 如何使用组合而不是继承?

C# 如何使用组合而不是继承?,c#,inheritance,C#,Inheritance,我有一个Configurator类,为了完成它的工作,它必须通过接口接收上下文对象: public class Configurator : IContextAware { private IContext _context; //property setter defined by the IContextAware interface public IContext Context { set { _context = value; } } // use

我有一个
Configurator
类,为了完成它的工作,它必须通过接口接收
上下文
对象:

public class Configurator : IContextAware
{
    private IContext _context;

    //property setter defined by the IContextAware interface
    public IContext Context { set { _context = value; } }

    //  use _context object in other methods here ...
}
我计划编写许多
Configurator
类型,它们都需要以相同的方式初始化它们的
\u上下文
字段。我的第一个想法是“为什么不激怒互联网上的每一个程序员并使用继承”

这样,我编写的任何其他需要上下文对象的类都可以直接从ContextInitializer继承,并直接使用上下文对象

优点:保证了一致的初始化,没有分散注意力,在每个类中都有重复的初始化代码

缺点:实现继承是邪恶的!,。。嗯,配置器不能从任何其他类继承

我应该澄清,无论如何,Configurator必须实现
IContextAware
接口。此外,该类必须具有默认/无参数构造函数,因此构造函数依赖项注入不是这里的选项

有人能建议如何使用组合来实现同样的好处,但设计更灵活,和/或描述上述继承解决方案的真正缺点吗?谢谢


注:如果有人好奇的话,这是从Spring.Net CodeConfig改编而来的。

我认为.Net基类库是回答此类问题的好标准。继承的使用永远不会被放入BCL,因为它将API的用户暴露给API内部。现在有一个基类没有任何语义意义。它的存在只是为了保存代码。所有公共API元素都应该有一个目的和语义

BCL的作者在API设计方面显然非常严格。我从未见过如此庞大而原始的字体收藏

也就是说,如果你不需要API清洁度,你就不需要遵守相同的标准并不是每一个API都会向数百万开发人员公开。在API纯度上做出一点妥协,以节省大量代码并消除冗余和潜在错误,这是一种合理的权衡


我的选择:我会使用您的方法来处理内部代码。对于公共API(想想Codeplex库等等),我宁愿复制多余的东西并保持公共API的表面干净。

我认为.NET基类库是回答这些问题的好标准。继承的使用永远不会被放入BCL,因为它将API的用户暴露给API内部。现在有一个基类没有任何语义意义。它的存在只是为了保存代码。所有公共API元素都应该有一个目的和语义

BCL的作者在API设计方面显然非常严格。我从未见过如此庞大而原始的字体收藏

也就是说,如果你不需要API清洁度,你就不需要遵守相同的标准并不是每一个API都会向数百万开发人员公开。在API纯度上做出一点妥协,以节省大量代码并消除冗余和潜在错误,这是一种合理的权衡


我的选择:我会使用您的方法来处理内部代码。对于公共API(想想Codeplex库等等),我宁愿复制多余的东西并保持公共API表面干净。

继承是邪恶的?我错过了那个备忘录。@Rik说实话,如果有人问我的话“是
配置程序
上下文初始值设定项?我不得不说不,但是使用了
contextinitializer
,因此这里暗示继承并不完全正确。绝对语句总是错误的。继承并不是天生的邪恶。这是一个工具。你可以用锤子把钉子钉在墙上,或者把某人的头骨敲开。这是你如何使用它,这可能是邪恶的。好吧,那么滥用遗产是邪恶的。明白了。@user1467261-你说得对,
Configurator
使用了
ContextInitializer
。那么,为什么不让构造函数成为
公共配置器(IContextInitializer contextInitializer){//use contextInitializer}
?(顺便说一句,如果您计划使用不同类型的上下文初始值设定项,我强烈建议使用接口)-一个很好的例子是。继承是邪恶的吗?我错过了那个备忘录。@Rik说实话,如果有人问我的话“是
配置程序
上下文初始值设定项?我不得不说不,但是使用了
contextinitializer
,因此这里暗示继承并不完全正确。绝对语句总是错误的。继承并不是天生的邪恶。这是一个工具。你可以用锤子把钉子钉在墙上,或者把某人的头骨敲开。这是你如何使用它,这可能是邪恶的。好吧,那么滥用遗产是邪恶的。明白了。@user1467261-你说得对,
Configurator
使用了
ContextInitializer
。那么,为什么不让构造函数成为
公共配置器(IContextInitializer contextInitializer){//use contextInitializer}
?(顺便说一句,如果您计划使用不同类型的上下文初始值设定项,我强烈建议您使用一个接口)-一个很好的例子是。
public class ContextInitializer: IContextAware
{
    // field to hold the injected context
    protected IContext _context;

    //property setter defined by the IContextAware interface
    public IContext Context { set { _context = value; } }
}

public class Configurator : ContextInitializer
{
    //  use _context object here ...
}