Vra

Die nuwe uitbreidings in .Netto 3.5 toelaat dat funksionaliteit te verdeel word uit koppelvlakke.

Byvoorbeeld in .Net 2.0

public interface IHaveChildren {
    string ParentType { get; }
    int ParentId { get; }

    List<IChild> GetChildren()
}

Kan (in 3.5) word:

public interface IHaveChildren {
    string ParentType { get; }
    int ParentId { get; }
}

public static class HaveChildrenExtension {
    public static List<IChild> GetChildren( this IHaveChildren ) {
        //logic to get children by parent type and id
        //shared for all classes implementing IHaveChildren 
    }
}

Hierdie lyk vir my na'n beter meganisme vir baie koppelvlakke.Hulle hoef nie meer'n abstrakte basis om deel hierdie kode, en funksioneel die kode werk dieselfde.Dit kan maak dat die kode meer te onderhou en makliker om te toets.

Die enigste nadeel is dat'n abstrakte basisse implementering kan'n virtuele, maar kan dit gewerk word om (sou'n geval metode steek'n uitbreiding metode met dieselfde naam?sou dit verwarrend wees-kode om dit te doen?)

Enige ander redes nie te gereeld gebruik van hierdie patroon?


Verduideliking:

Ja, ek sien die tendens met die uitbreiding metodes is aan die einde met hulle oral.Ek wil wees veral versigtig met enige op .Netto waarde tipes sonder'n groot deel van die peer review (ek dink die enigste een wat ons het op'n string is'n .SplitToDictionary() - soortgelyk aan .Split() maar die neem van'n sleutel-waarde delimiter te)

Ek dink daar is'n hele beste praktyk debat daar ;-)

(Terloops:DannySmurf, jou PM klink scary.)

Ek is spesifiek vra hier oor die gebruik van uitbreiding metodes waar ons voorheen gehad het koppelvlak metodes.


Ek probeer om te verhoed dat baie van die vlakke van abstrakte basis klasse - die klasse implementering van hierdie modelle meestal reeds basis klasse.Ek dink hierdie model kan wees om meer te onderhou en minder té-tesame as die toevoeging van verdere voorwerp hiërargieë.

Is dit wat ME gedoen het om te IEnumerable en IQueryable vir Linq?

Was dit nuttig?

Oplossing

Ek dink die oordeelkundige gebruik van uitbreiding metodes sit koppelvlakke op 'n meer equatable posisie met (abstrakte) basis klasse.

Versioning. Een voordeel basis klasse het oor koppelvlakke is dat jy maklik nuwe virtuele lede kan byvoeg in 'n latere weergawe, terwyl die toevoeging van lede tot 'n koppelvlak sal implementeerders gebou teen die ou weergawe van die biblioteek te breek. In plaas daarvan, 'n nuwe weergawe van die koppelvlak met die nuwe lede moet geskep word, en die biblioteek sal hê om rond te werk of toegang tot nalatenskap beperk voorwerpe net die uitvoering van die oorspronklike koppelvlak.

As 'n konkrete voorbeeld, die eerste weergawe van 'n biblioteek kan 'n koppelvlak definieer soos so:

public interface INode {
  INode Root { get; }
  List<INode> GetChildren( );
}

As die biblioteek het vrygestel, ons kan nie die koppelvlak verander sonder om te breek huidige gebruikers. In plaas daarvan, in die volgende release ons nodig sou wees om 'n nuwe koppelvlak definieer om bykomende Funksionaliteit voeg:

public interface IChildNode : INode {
  INode Parent { get; }
}

Daar is egter slegs gebruikers van die nuwe biblioteek sal in staat wees om die nuwe koppelvlak implementeer. Ten einde te werk met die nalatenskap kode, moet ons die ou implementering, wat 'n uitbreiding metode mooi kan hanteer aanpas:

public static class NodeExtensions {
  public INode GetParent( this INode node ) {
    // If the node implements the new interface, call it directly.
    var childNode = node as IChildNode;
    if( !object.ReferenceEquals( childNode, null ) )
      return childNode.Parent;

    // Otherwise, fall back on a default implementation.
    return FindParent( node, node.Root );
  }
}

Nou alle gebruikers van die nuwe biblioteek kan hanteer beide nalatenskap en moderne implementering identies.

oorlaai. Nog 'n gebied waar uitbreiding metodes nuttig kan wees in die verskaffing van oorbelasting vir koppelvlak metodes. Jy kan 'n metode met verskeie parameters om sy optrede, waarvan slegs die eerste een of twee is belangrik in die 90% geval beheer het. Sedert C # nie toelaat dat die opstel van standaard waardes vir parameters, gebruikers óf die volle parameters metode noem elke keer, of elke implementering moet die triviale oorlaai vir die kern metode te implementeer.

In plaas uitbreiding metodes kan gebruik word om die triviale oorlading implementering verskaf:

public interface ILongMethod {
  public bool LongMethod( string s, double d, int i, object o, ... );
}

...
public static LongMethodExtensions {
  public bool LongMethod( this ILongMethod lm, string s, double d ) {
    lm.LongMethod( s, d, 0, null );
  }
  ...
}

Neem asseblief kennis dat beide van hierdie gevalle is opgeteken in terme van die bedrywighede wat deur die poorte, en betrek triviale of bekende standaard implementering. Dit gesê, jy kan net in besit van 'n klas een keer, en die regspraak gebruik van uitbreiding metodes kan 'n waardevolle manier om te gaan met 'n paar van die dienste wat deur die basis klasse niceties wat koppelvlakke gebrek verskaf:)


Edit: 'n verwante post deur Joe Duffy: Uitbreiding metodes as standaard koppelvlak metode implementering

Ander wenke

Uitbreiding metodes moet gebruik word as net dat:uitbreidings.Enige belangrike struktuur/ontwerp verwante kode of nie-triviale werking gestel moet word in'n voorwerp wat is saamgestel in/geërf het van'n klas of koppelvlak.

Een keer'n ander voorwerp probeer om te gebruik om die uitgebreide een, hulle sal nie sien nie die uitbreidings en dalk het om dit te reimplement/re-verwysing hulle weer.

Die tradisionele wysheid is dat die Uitbreiding metodes moet slegs gebruik word vir:

  • nut klasse, soos Vaibhav genoem
  • die uitbreiding van verseël 3rd party APIs

Ek dink die beste ding wat uitbreiding metodes vervang is almal nut klasse wat jy vind in elke projek.

Ten minste vir nou, ek voel dat enige ander gebruik van Uitbreiding metodes verwarring sou veroorsaak in die werkplek.

My twee stukkies.

Ek sien die skeiding van die domein / model en UI / view funksies met behulp van uitbreiding metodes as 'n goeie ding, veral omdat hulle in aparte naamruimtes kan woon.

Byvoorbeeld:

namespace Model
{
    class Person
    {
        public string Title { get; set; }
        public string FirstName { get; set; }
        public string Surname { get; set; }
    }
}

namespace View
{
    static class PersonExtensions
    {
        public static string FullName(this Model.Person p)
        {
            return p.Title + " " + p.FirstName + " " + p.Surname;
        }

        public static string FormalName(this Model.Person p)
        {
            return p.Title + " " + p.FirstName[0] + ". " + p.Surname;
        }
    }
}

Op hierdie manier uitbreiding metodes kan insgelyks gebruik word om XAML data templates. Jy kan nie toegang tot private / beskerm lede van die klas, maar dit kan die data onttrekking gehandhaaf moet word sonder oormatige kode duplisering regdeur die aansoek.

Daar is niks verkeerd met die uitbreiding van koppelvlakke, in werklikheid dit is hoe LINQ werk aan die uitbreiding metodes toe te voeg tot die versameling klasse.

Dit gesê, jy moet regtig net dit te doen in die geval waar jy nodig het om dieselfde funksie in alle klasse wat dit koppelvlak implementeer verskaf en dat funksie is nie (en waarskynlik moet nie) deel van die "amptelike" implementering van enige afgeleide klasse. Die uitbreiding van 'n koppelvlak is ook goed as dit is net onprakties om 'n verlenging metode vir elke moontlike afgelei tipe wat die nuwe funksionaliteit vereis skryf.

Ek sien 'n klomp mense pleit met behulp van 'n basis klas om algemene funksies deel. Wees versigtig met hierdie - moet jy samestelling guns oor erfenis. Erfenis moet slegs gebruik word vir polimorfisme, wanneer dit sinvol uit 'n model oogpunt. Dit is nie 'n goeie hulpmiddel vir kode hergebruik.

As vir die vraag: Wees ware van die beperkinge wanneer dit te doen - byvoorbeeld in die getoon kode, met behulp van 'n uitbreiding metode om effektief te implementeer GetChildren 'robbe' hierdie implementering en nie toelaat dat enige IHaveChildren Tenuitvoerlegging om sy eie te voorsien indien nodig. As dit is OK, dan hoef ek omgee die uitbreiding metode benadering dat daar nog baie. Dit is nie in klip, en kan gewoonlik maklik refactored wanneer meer buigsaamheid later nodig is.

Vir groter buigsaamheid, met behulp van die strategie patroon kan beter wees. Iets soos:

public interface IHaveChildren 
{
    string ParentType { get; }
    int ParentId { get; }
}

public interface IChildIterator
{
    IEnumerable<IChild> GetChildren();
}

public void DefaultChildIterator : IChildIterator
{
    private readonly IHaveChildren _parent;

    public DefaultChildIterator(IHaveChildren parent)
    {
        _parent = parent; 
    }

    public IEnumerable<IChild> GetChildren() 
    { 
        // default child iterator impl
    }
}

public class Node : IHaveChildren, IChildIterator
{ 
    // *snip*

    public IEnumerable<IChild> GetChildren()
    {
        return new DefaultChildIterator(this).GetChildren();
    }
}

'n bietjie meer.

As veelvuldige koppelvlakke het dieselfde handtekening uitbreiding metode, sal jy nodig het om die oproeper uitdruklik te skakel na 'n koppelvlak tipe en dan bel die metode. Bv.

((IFirst)this).AmbigousMethod()

Ouch. Moet asseblief nie Interfaces brei.
'N koppelvlak is 'n skoon kontrak wat 'n klas moet implementeer, en jou gebruik van die genoemde klasse moet word beperk tot wat in die kern Interface vir hierdie om korrek te werk.

Dit is hoekom jy altyd verklaar die koppelvlak as die tipe plaas van die werklike klas.

IInterface variable = new ImplementingClass();

Op die oomblik?

As jy regtig 'n kontrak met 'n paar bykomende funksies nodig, abstrakte klasse is jou vriende.

Rob Connery (Subsonic en MVC gebou op te neem) geïmplementeer 'n IRepository-agtige patroon in sy gebou op aansoek. Dit is nie heeltemal die patroon hierbo, maar dit beteken deel 'n paar ooreenkomste.

Die data laag terugkeer IQueryable wat die beslag laag te filter en sorteer uitdrukking van toepassing op die top van dat permitte. Die bonus is in staat om 'n enkele GetProducts metode spesifiseer, byvoorbeeld, en dan besluit op gepaste wyse in die beslag laag hoe jy wil dat sorteer, filter of selfs net 'n bepaalde reeks van resultate.

Nie 'n tradisionele benadering, maar baie cool en beslis 'n geval van droog.

Een probleem wat ek kan sien is dat, in'n groot maatskappy, hierdie patroon kan toelaat dat die kode te moeilik (indien nie onmoontlik nie) vir almal om te verstaan en te gebruik.Indien verskeie ontwikkelaars is voortdurend die toevoeging van hul eie metodes om bestaande klasse, skei van dié klasse (en, God help ons almal, om te BCL klasse selfs), kon ek sien'n kode basis spin buite beheer eerder vinnig.

Selfs in my eie werk het, kon ek sien dit gebeur, met my PM se begeerte om by te voeg elke bietjie van die kode wat ons werk op om óf die UI of die data toegang laag, ek kan heeltemal sien hom aan te dring op 20 of 30 metodes word bygevoeg tot die Stelsel.String wat slegs tangensiaal-wat verband hou met string hantering.

Ek moes iets soortgelyks op te los: Ek wou 'n Lys geslaag om die uitbreidings funksie het waar IIDable is 'n koppelvlak wat 'n funksie lang getId () het. Ek het probeer om met behulp van GetIds (hierdie lys bla), maar die samesteller nie toelaat dat my om dit te doen. Ek gebruik templates plaas en tik gegooi binne-in die funksie om die tipe koppelvlak. Ek benodig hierdie funksie vir 'n paar linQ te genereer klasse SQL.

Ek hoop dit help:)

    public static List<long> GetIds<T>(this List<T> original){
        List<long> ret = new List<long>();
        if (original == null)
            return ret;

        try
        {
            foreach (T t in original)
            {
                IIDable idable = (IIDable)t;
                ret.Add(idable.getId());
            }
            return ret;
        }
        catch (Exception)
        {
            throw new Exception("Class calling this extension must implement IIDable interface");
        }
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top