使用静态包装器直接调用无处不在的接口包装类时的快捷方式和建议?

Posted

技术标签:

【中文标题】使用静态包装器直接调用无处不在的接口包装类时的快捷方式和建议?【英文标题】:Shortcuts, Suggestions When Using Static Wrappers for Direct Function Calls to Ubiquitous Interface-Wrapped Classes? 【发布时间】:2012-03-19 17:53:01 【问题描述】:

因此,我(大部分)都围绕着 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) 隐式运算符,一个 la,hcb 的建议:

http://www.codeproject.com/Articles/10072/Simulated-Multiple-Inheritance-Pattern-for-C

为什么? 这种方法需要您为使用组件类的所有类创建运算符,这会导致在常用接口的方案中产生更多代码。对我来说,如果你打算走那条路,只需制作传统的包装器函数,而不是花哨的东西。

我对更优雅的解决方案的需求是由普遍和大量使用的几个通用组件驱动的,这些组件执行冗余功能,但不相似,因此不适合集中在一个类中(尽管会提供便利)。

编辑 3:

感谢svick 向我展示如何在不进行编辑潜水的情况下很好地格式化我的代码! :)

重新命名问题以使其更清晰,添加更精确的要求以提出替代解决方案。

【问题讨论】:

您是否尝试过重构工具,例如ReSharper? 不...对 C-Sharp 来说相对较新,但正在构建一个框架,因此需要一些无处不在的组件,因此我是如何使用该语言的这一特性的。您会推荐 ReSharper 吗?它是否满足了我的上述一些需求(或提供了比上述方法更好的替代方案?)? 【参考方案1】:

您所做的只是试图模拟多重继承。我不认为这是“添加组件的一般方法”。

我不认为您正在做的事情是使用扩展方法的好方法,它对我来说更像是一种反模式。尤其是因为您这样做只是为了节省一些击键次数,因此不会给您带来任何其他好处。

我认为对于您为什么不能使用更简单的方法来做到这一点的问题的答案是 C# 尝试explicitconsistent

明确表示它不会猜测你的意思,它会让你拼出来。这是因为它的猜测很容易出错。它究竟如何猜测的规则可能必须非常复杂,因此令人困惑。 (“我做了这个小改动,现在我的代码行为完全不同了。”)

另一件事是一致性:如果您通常以一种方式实现接口,但有时您会以不同的方式实现,这会使语言更加复杂和混乱。当然,在某些情况下,像这样的不一致是值得的。

具体来说,如果从接口自动实现属性的功能可以工作,您的代码会编译,但不能正常工作IBladeEquipped 定义了属性blade,但是您的类包含属性mrPointy。编译器会看到您没有实现所需的属性并为您实现它。然后你的代码会因为NullReferenceException 而失败,因为blade 将永远是null。因此,我认为您的代码提供了一个很好的论据来反对该功能。

另外,我认为您的示例实际上很好地解释了为什么您不应该按照您想要的方式编写代码。如果您想重新磨碎绞肉机的刀,请这样做:grinder.blade.Resharpen()。以不同的方式写出来会让我感觉不那么自然,更令人困惑。

【讨论】:

【参考方案2】:

我不确定这是否是您要寻找的,但我喜欢将接口与抽象基类结合起来以实现默认方法和属性:

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;  

【讨论】:

嗨 hcb... 但是你能同时从多个抽象类继承吗?例如public class MeatGrinder : BHasGear, BHasBlade??我需要能够使用多个接口! 如果我理解正确,抽象类的多重继承不会是非法的......我想我应该在我的描述中放置两个使用的接口(刀片和齿轮),但我认为那会我不只是继承这一事实暗示了这一点! :) 确实,您只能从一个(抽象)类继承,但可以从多个接口继承。这应该有某种设计模式 这里是:codeproject.com/Articles/10072/… @hcb... 确实很灵活,它比我上面概述的方法要多得多,在你有少量常用接口的情况下(说很多事情GearBlade 组件),但使用这些接口的类的数量。因此,您发布的代码将起作用(很像上面的代码),但据我了解,这会使我的生活更加困难,而不是更简单。

以上是关于使用静态包装器直接调用无处不在的接口包装类时的快捷方式和建议?的主要内容,如果未能解决你的问题,请参考以下文章

函数包装器静态检查 HTTP 响应的参数

用于 C++ 的 C# 包装器,但仅编译为静态库

通过在 C++ 接口周围创建 C 包装器,在 FORTRAN 中调用 C++ dll 文件 [关闭]

什么是包装类?

C# 使用 CLI 包装器调用非托管 C++

如何在 Java 中实现包装装饰器?