“编程到接口"使用扩展方法:它什么时候走得太远? [英] "Program to an interface" using extension methods: When does it go too far?

查看:13
本文介绍了“编程到接口"使用扩展方法:它什么时候走得太远?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:本着"编程到接口,而不是实现"Haskell 类型类a>,作为一个编码实验,我在思考创建一个主要基于接口和扩展方法组合的 API 意味着什么.我有两个准则:

Background: In the spirit of "program to an interface, not an implementation" and Haskell type classes, and as a coding experiment, I am thinking about what it would mean to create an API that is principally founded on the combination of interfaces and extension methods. I have two guidelines in mind:

  1. 尽可能避免类继承.接口应该实现为密封类es.
    (这有两个原因:首先,因为子类化提出了一些关于如何在其派生类中指定和强制执行基类契约的令人讨厌的问题.其次,这是 Haskell 类型类的影响,多态性不需要子类化.)

尽可能避免实例方法.如果可以通过扩展方法来完成,这些是首选.
(这是为了帮助保持接口紧凑:可以通过其他实例方法的组合来完成的所有事情都变成了扩展方法.接口中保留的是核心功能,尤其是状态更改方法.)

Avoid instance methods wherever possible. If it can be done with extension methods, these are preferred.
(This is intended to help keep the interfaces compact: Everything that can be done through a combination of other instance methods becomes an extension method. What remains in the interface is core functionality, and notably state-changing methods.)

问题:我对第二条准则有疑问.考虑一下:

Problem: I am having problems with the second guideline. Consider this:

interface IApple { }
static void Eat(this IApple apple)
{
    Console.WriteLine("Yummy, that was good!");
}

interface IRottenApple : IApple { }
static void Eat(this IRottenApple apple)
{
    Console.WriteLine("Eat it yourself, you disgusting human, you!");
}

sealed class RottenApple : IRottenApple { }
IApple apple = new RottenApple();
// API user might expect virtual dispatch to happen (as usual) when 'Eat' is called:
apple.Eat(); // ==> "Yummy, that was good!"

显然,对于预期的结果(Eat it yourself..."),Eat 应该是一个常规的实例方法.

Obviously, for the expected outcome ("Eat it yourself…"), Eat ought to be a regular instance method.

问题:关于使用扩展方法与(虚拟)实例方法的改进/更准确的指南是什么?什么时候使用扩展方法来编程到接口"会走得太远?在什么情况下实际上需要实例方法?

Question: What would be a refined / more accurate guideline about the use of extension methods vs. (virtual) instance methods? When does the use of extension methods for "programming to an interface" go too far? In what cases are instance methods actually required?

我不知道是否有任何明确的、通用的规则,所以我不期待一个完美的、通用的答案.感谢对上述指南 (2) 的任何有充分论证的改进.

I don't know if there is any clear, general rule, so I am not expecting a perfect, universal answer. Any well-argued improvements to guideline (2) above are appreciated.

推荐答案

你的指导方针已经足够好了:它已经说尽可能".因此,任务实际上是在更多细节中阐明尽可能"这一点.

Your guideline is good enough as it is: it already says "wherever possible". So the task is really to spell out the "wherever possible" bit in some more details.

我使用这个简单的二分法:如果添加方法的目的是隐藏子类之间的差异,则使用扩展方法;如果目的是突出差异,请使用虚拟方法.

I use this simple dichotomy: if the purpose of adding a method is to hide the differences among subclasses, use an extension method; if the purpose is to highlight the differences, use a virtual method.

你的 Eat 方法是一个在子类之间引入差异的方法的例子:吃(或不吃)苹果的过程取决于它是什么种类的苹果.因此,您应该将其实现为实例方法.

Your Eat method is an example of a method that introduce a difference among subclasses: the process of eating (or not) an apple depends on what kind of apple it is. Therefore, you should implement it as an instance method.

试图隐藏差异的方法示例是 ThrowAway:

An example of a method that tries to hide the differences would be ThrowAway:

public static void ThrowAway(this IApple apple) {
    var theBin = RecycleBins.FindCompostBin();
    if (theBin != null) {
        theBin.Accept(apple);
        return;
    }
    apple.CutUp();
    RecycleBins.FindGarbage().Accept(apple);
}

如果扔掉苹果的过程与苹果的种类无关,则该操作是在扩展方法中实现的主要候选者.

If the process of throwing away an apple is the same regardless of the kind of the apple, the operation is a prime candidate for being implemented in an extension method.

这篇关于“编程到接口"使用扩展方法:它什么时候走得太远?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆