Domanda

Quindi ho avuto a che fare con diverse API recentemente fornite da diversi produttori di software per i loro prodotti. A volte mancano le cose, a volte voglio solo rendere il codice più leggibile e sto cercando di evitare una tonnellata di metodi statici in cui non appartengono a " ottieni ciò di cui ho bisogno " dalle API. Quindi, mi sono trovato a scrivere alcuni metodi di estensione.

Tuttavia, poiché esistono molti metodi e nell'interesse di mantenere " my " metodi separati da quelli degli oggetti API in termini di leggibilità del codice, ho pensato a questo piccolo bocconcino:

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;
    }

}

Quindi posso fare cose come:

string awesome = instanceOfApiObject.MTPAEC.SomeMethod();

e ho una netta separazione delle mie cose dalle loro.

Ora la mia domanda è ... sembra una buona pratica, migliorare la leggibilità del codice ... o è una cattiva idea? Ci sono conseguenze dannose nel fare questo?

Disclaimer: Il codice sopra è solo per dimostrare il concetto. Ovviamente c'è un miglior controllo di integrità e utilità nella cosa reale.

Suppongo che lo stesso livello di separazione possa essere semplicemente fatto in questo modo:

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;
    }

}
È stato utile?

Soluzione

Per rispondere alla tua domanda diretta, penso che passare attraverso i guai in più per separare la tua funzionalità dalla funzionalità di base sia un cattivo odore di codice. Non preoccuparti di avere il tuo codice separato dal loro codice dal punto di vista dell'utilizzo. In primo luogo rende molto più difficile trovare quello che stai cercando poiché ora ci sono due posti in cui cercare la stessa funzionalità e in secondo luogo la sintassi fa sembrare che le tue estensioni stiano funzionando sulla proprietà MTPAEC e non sull'oggetto principale (che loro sono).

Il mio suggerimento è di utilizzare metodi di estensione reali che ti consentano di averlo, ma senza il costruttore aggiuntivo.

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;
    }
}

utilizzato da

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

C # farà il resto.

Guardando il tuo suggerimento sopra, dovresti dividere le due classi, credo. Uno per fornire gruppi di estensioni utilizzando il meccanismo di estensioni e un altro per fornire ogni gruppo di logica.

Se devi separare il tuo da un colpo d'occhio, usa una convenzione di denominazione per rendere il tuo look unico. Sebbene al passaggio del mouse e attraverso l'intellisense ti dirà che si tratta di un metodo di estensione.

Se vuoi solo la separazione dei contenuti come te, allora avrai bisogno di due classi.

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;
    }
}

Altri suggerimenti

Quando si ha a che fare con un'API che non è possibile modificare, i metodi di estensione sono un modo ragionevole per estendere l'espressività dell'API rimanendo relativamente disaccoppiati, IMHO.

Il problema più grande con i metodi di estensione ha a che fare con il fatto che essi sono implicitamente dedotti per essere disponibili in base all'inclusione dello spazio dei nomi (le istruzioni using nella parte superiore del file). Di conseguenza, se dimentichi semplicemente di includere uno spazio dei nomi, puoi finire per grattarti la testa chiedendoti perché non è disponibile.

Vorrei anche aggiungere che i metodi di estensione non sono un costrutto ovvio, e di conseguenza gli sviluppatori non si aspettano o anticipano comunemente. Tuttavia, con il maggiore utilizzo di LINQ, immagino che sempre più sviluppatori si sentiranno a proprio agio con il loro uso.

La mia opinione è che stai aggiungendo inutilmente un ulteriore livello di riferimento indiretto. Vuoi che i metodi di estensione siano disponibili sugli oggetti originali ... quindi perché non metterli lì? Intellisense ti farà sapere che gli oggetti sono estensioni, per il raro caso a cui tieni davvero.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top