使用扩展方法来提高代码可读性

时间:2009-10-27 17:22:40

标签: c# .net extension-methods

因此,我一直在处理不同软件供应商最近为其产品提供的几个API。有时事情是缺乏的,有时候我只是想让代码更具可读性,而我正试图避免大量的静态方法,因为它们不属于API中的“得到我需要的东西”。因此,我发现自己编写了很多扩展方法。

然而,因为有很多方法,并且为了在代码可读性方面将“我的”方法与API对象的方法分开,我想出了这个小小的想法:

public class MyThirdPartyApiExtensionClass {

    public static MyThirdPartyApiExtensionClass MTPAEC(this ThirdPartyApiClass value) {
        return new MyThirdPartyApiExtensionClass(value);
    }

    private ThirdPartyApiClass value;

    public MyThirdPartyApiExtensionClass(ThirdPartyApiClass extendee) {
        value = extendee;
    }

    public string SomeMethod() {
        string foo = value.SomeCrappyMethodTheProviderGaveUs();
        //do some stuff that the third party api can't do that we need
        return foo;
    }

    public int SomeOtherMethod() {
        int bar = value.WowThisAPISucks(null);
        //more stuff
        return bar;
    }

}

然后我可以做以下事情:

string awesome = instanceOfApiObject.MTPAEC.SomeMethod();

我把他的东西与他们的东西分开了。

现在我的问题是......这看起来像是一种很好的做法,提高了代码的可读性......或者这是一个坏主意?这样做有什么不良后果吗?

声明: 上面的代码只是为了演示这个概念。显然,在真实事物中有更好的理智检查和有用性。

我认为可以简单地完成相同级别的分离:

public static class MyThirdPartyApiExtensionClass {

    public ThirdPartyApiClass MTPAEC(this ThirdPartyApiClass value) {
        return value;
    }

    public string SomeMethod(this ThirdPartyApiClass value) {
        string foo = value.SomeCrappyMethodTheProviderGaveUs();
        //do some stuff that the third party api can't do that we need
        return foo;
    }

    public int SomeOtherMethod(this ThirdPartyApiClass value) {
        int bar = value.WowThisAPISucks(null);
        //more stuff
        return bar;
    }

}

3 个答案:

答案 0 :(得分:2)

在处理无法修改的API时,扩展方法是扩展API表现力的合理方式,同时保持相对分离,恕我直言。

扩展方法的最大问题与它们被隐式推断为基于命名空间包含(文件顶部的using语句)可用的事实有关。因此,如果您只是忘记包含一个命名空间,那么您最终可能会想到为什么没有这个命名空间。

我还要补充说,扩展方法不是一个明显的构造,因此开发人员通常不会期望或预期它们。但是,随着LINQ的使用越来越多,我认为越来越多的开发人员会对它们的使用感到满意。

答案 1 :(得分:2)

要回答您的直接问题,我认为通过额外的麻烦将您的功能与基本功能分开是一个糟糕的代码味道。从使用角度来看,不要担心代码与代码分离。首先它使找到你想要的东西变得更加困难,因为现在有两个地方可以寻找相同的功能,其次语法使你的扩展看起来像是在MTPAEC属性而不是核心对象(它们是是)。

我的建议是使用实际的扩展方法,允许你拥有它,但没有额外的构造函数。

public static class ApiExtension
{
    public static string SomeMethod(this ThirdPartyApiClass value)
    {
        string foo = value.SomeCrappyMethodTheProviderGaveUs();
        //do some stuff that the third party api can't do that we need
        return foo;
    }
}

使用

var mine = new ThirdPartyApiClass();
mine.SomeMethod();

C#将完成其余的工作。

看看你的上述建议,我认为你必须将这两个课分开。一个用于使用扩展机制提供扩展组,另一个用于提供每组逻辑。

如果您需要一目了然地使用命名约定,那么请使用命名约定来使您的外观独一无二。虽然在徘徊和通过intellisense它会告诉你它是一种扩展方法。

如果你只想要像你一样分离内容,那么你需要两个类。

public static class ApiExtensionder
{
    public static MTPAEC(this ThirdPartyApiClass value)
    {
        return new MtpaecExtensionWrapper(value);
    }
}

public class MtpaecExtensionWrapper
{
    private ThirdPartyApiClass wrapped;

    public MtpaecExtensionWrapper(ThirdPartyApiClass wrapped)
    {
        this.wrapped = wrapped;
    }

    public string SomeMethod()
    {
        string foo = this.wrapped.SomeCrappyMethodTheProviderGaveUs();
        //do some stuff that the third party api can't do that we need
        return foo;
    }
}

答案 2 :(得分:0)

我的观点是你不必要地增加了额外的间接水平。您希望扩展方法在原始对象上可用...那么为什么不将它们放在那里? Intellisense会告诉您对象是扩展名,对于您真正关心的罕见情况。

相关问题