快捷方式,使用静态包装器直接调用泛接口包装类时的建议
本文关键字:包装类 接口 调用 静态 包装 快捷方式 | 更新日期: 2023-09-27 18:26:29
所以我(大部分)都在思考C#的组件化范式,以及为什么这是一个更好(更可预测、更灵活)的替代方案,可以替代令人困惑和准不可预测的C++多重继承。
然而,我有几件事困扰着我。
因此,如果我理解正确,添加组件的一般方法是:
-
创建一个具有名称为
I<ClassName adjective>
的组件的接口public interface IHasGear { Gear gear { get; set; } } public interface IBladeEquipped { Blade blade { get; set; } }
-
创建一个扩展类,在接口类中调用适当的方法。
public static class GearExtensions { public static void Stop(this IHasGear machine) { machine.gear.KineticStop(); } public static void Accelerate(this IHasGear machine) { machine.gear.ApplyAngularAcceleration(); } } public static class BladeExtensions { public static void Cut(this IBladeEquipped machine) { machine.blade.Cut(); } public static void ReSharpen(this IBladeEquippeded machine) { machine.blade.ReSharpen(); } }
-
然后最后将接口引用和引用类的实例添加到使用所选组件的类中。
public class MeatGrinder : IHasGear, IHasBlade { public Gear oldToothyOne { get; set; } public Blade mrPointy { get; set; } public MeatGrinder() { oldToothyOne = new Gear(); mrPointy = new Blade();} }
现在我有几个问题:
-
为什么总是强制实例化var?
我知道,如果有继承,您可能想要这样,因为您可以用不同的子级实现var。但是最简单的非继承情况呢?为什么不建立一个自动机制,在编译的代码中自动实现接口中的基类,如果它们没有显式实现的话
-
有没有一种方法可以以无处不在的方式将这个过程模板化?
显然,如果您有几个组件,这是一个重复的任务。考虑到这种模糊性,有没有一种方法可以简化工作量??
-
是否有比我描述的方法更高级的组件化(/继承)方案?
需要牢记的事项:
- 只有几个组件类
- 我希望能够在复合类中使用组件类函数作为直接调用
- 有多个复合类(组件类<<复合类)
- 组件是不同的,因此不适合在一个类中进行统一
- 考虑到以上考虑,强迫我为每个组合类编写个性化代码的方法不是一种理想的方法
编辑1:
我不应该含糊其辞。我之所以不在这里使用直接继承,是因为我有多个"关键"组件,它们具有我希望能够直接公开解决的功能。。。例如,我想说:
Machine myMachine = new Machine();
myMachine.Accelerate();
myMachine.Cut();
myMachine.ReSharpen();
希望这有助于澄清我的问题以及我为什么采用这个方案。
此外,我的示例代码中有几个错误(var是非公共的,我的命名是一致的……这些都已经纠正了。
编辑2:
对我来说没有意义的事情(据我所知):
a) 抽象类
为什么没有多重继承
b) 隐式算子,a la,hcb的建议:
http://www.codeproject.com/Articles/10072/Simulated-Multiple-Inheritance-Pattern-for-C
为什么这种方法要求您使用组件类为任何类创建运算符,这将导致在通常使用接口的方案中产生更多的代码。对我来说,如果你要走这条路,只需要制作传统的包装器函数,而不是花里胡哨。
我对一个更优雅的解决方案的需求是由两个通用组件的普遍性和大量使用驱动的,这些组件执行冗余功能,但不同,因此不适合集中在一个类中(尽管这会提供便利)。
编辑3:
svick的道具向我展示了如何在不进行编辑的情况下很好地格式化我的代码!:)
取消了这个问题以使其更加清晰,增加了建议替代解决方案的更精确要求。
您所做的只是尝试模拟多重继承。我不认为这是"添加组件的一般方法"。
我不认为你所做的是使用扩展方法的好方法,对我来说,这更像是一种反模式。尤其是因为你这样做只是为了节省一些按键,所以不会给你带来任何其他好处。
我认为,对于你为什么不能使用更简单的方法来做到这一点的问题,答案是C#试图做到显式和一致性。
明确地说,它不会猜测你的意思,它会让你把它拼出来。这是因为它的猜测很容易出错。它猜测的规则可能非常复杂,因此令人困惑。("我做了这个小改动,现在我的代码表现完全不同了。")
另一件事是一致性:如果您通常以一种方式实现接口,但有时以不同的方式实现,则会使语言更加复杂和混乱。当然,在某些情况下,像这样的不一致是值得的
具体地说,如果从接口自动实现属性的功能可以工作,那么您的代码将编译,但不能正常工作:IBladeEquipped
定义了属性blade
,但您的类包含属性mrPointy
。编译器会发现您没有实现所需的属性,并为您实现它。然后您的代码将以NullReferenceException
失败,因为blade
将始终是null
。所以我认为您的代码提供了一个很好的论据来反对这个特性。
此外,我认为您的示例实际上很好地解释了为什么不应该按照您想要的方式编写代码。如果你想重新打磨绞肉机的刀,可以这样做:grinder.blade.Resharpen()
。以不同的方式编写它会让我感觉不那么自然,也更困惑。
我不确定这是否是你想要的,但我喜欢将接口与抽象基类结合起来,以实现默认方法和属性:
public interface IHasGear { Gear gear { get; set; } }
public abstract class BHasGear : IHasGear { public virtual Gear gear { get; set; } }
public class MeatGrinder : BHasGear
{
//no need to implement gear, the abstract class already implemented it
private Gear oldToothyOne { get; set; } }
}