Кеңейту әдісі - Extension method - Wikipedia

Жылы объектіге бағытталған компьютерлік бағдарламалау, an кеңейту әдісі Бұл әдіс объектіге бастапқы объект болғаннан кейін қосылды құрастырылған. Модификацияланған объект көбінесе класс, прототип немесе тип болып табылады. Кеңейту әдістері дегеніміз - кейбір объектіге бағытталған бағдарламалау тілдерінің ерекшеліктері. Кеңейту әдісін шақыру мен тип анықтамасында жарияланған әдісті шақырудың синтаксистік айырмашылығы жоқ.[1]

Алайда барлық тілдер кеңейту әдістерін бірдей қауіпсіз деңгейде қолданбайды. Мысалы, C #, Java (Manifold арқылы) және Kotlin сияқты тілдер кеңейтілген класты ешбір өзгертпейді, өйткені бұл класс иерархияларын бұзып, виртуалды әдіс диспетчерлеуге кедергі келтіруі мүмкін. Сондықтан бұл тілдер кеңейту әдістерін қатаң түрде жүзеге асырады және оларды шақыру үшін статикалық диспетчерлеуді қолданады.

Бағдарламалау тілдеріндегі қолдау

Кеңейту әдістері - көптеген тілдердің ерекшеліктері, соның ішінде C #, Java арқылы Манифольд, Госу, JavaScript, Оттегі, Рубин, Smalltalk, Котлин, Дарт, Visual Basic.NET және Xojo. Сияқты динамикалық тілдерде Python, кеңейту әдісі тұжырымдамасы қажет емес, өйткені сыныптарды арнайы синтаксиссіз кеңейтуге болады («маймылдарды жамау» деп аталатын тәсіл, мысалы, кітапханаларда жұмыс істейді). гевент ).

VB.NET және Oxygene-де олар «кеңейту«кілт сөз немесе төлсипат. Xojo-да»Ұзартылады«кілт сөз ғаламдық әдістермен қолданылады.

C # олар статикалық сыныптарда статикалық әдістер ретінде жүзеге асырылады, олардың бірінші аргументі кеңейтілген сынып және оның алдында «бұл«кілт сөз.

Java-да сіз кеңейту әдістерін қосасыз Манифольд, сіз өзіңіздің жобаңыздың класс жолына қосылатын құмыра файлын. Java # кеңейту әдісіне ұқсас, an-да статикалық деп жарияланады @ Кеңейту бірінші аргумент кеңейтілген сыныппен бірдей типке ие және түсіндірмесі берілген класс @ Бұл.

Smalltalk-та кез-келген код кез-келген уақытта әдіс құру туралы хабарлама жіберу арқылы кез-келген сыныпқа әдісті қоса алады әдістері:) қолданушы кеңейтуді қалайтын сыныпқа. Smalltalk әдісі санаты шартты түрде жұлдызшамен қоршалған кеңейтуді қамтамасыз ететін буманың атымен аталады. Мысалы, Etoys қосымшасының коды негізгі кітапханадағы сабақтарды кеңейткенде, қосылған әдістер * этойлар * санат.

Ruby-де, Smalltalk сияқты, кеңейтуге арналған арнайы тілдік мүмкіндік жоқ, өйткені Ruby сыныптарды кез-келген уақытта қайтадан ашуға мүмкіндік береді сынып кілт сөз, бұл жағдайда жаңа әдістер қосу керек. Рубин қауымдастығы кеңейту әдісін көбінесе өзіндік түрі ретінде сипаттайды маймыл патч. Сондай-ақ, объектілерге қауіпсіз / жергілікті кеңейтімдерді қосудың жаңа мүмкіндігі бар, деп аталады Нақтылау, бірақ аз қолданылғаны белгілі.

Свифтте кеңейту кілт сөз бар классқа әдістерді, конструкторлар мен өрістерді қосуға мүмкіндік беретін классқа ұқсас конструкцияны белгілейді, оның ішінде жаңа классқа жаңа интерфейс / хаттама енгізу мүмкіндігі де бар.

Кеңейту әдістері мүмкіндік ретінде

Өзгелер жазған кодты төменде сипатталғандай кеңейтуге мүмкіндік беретін кеңейту әдістерінің жанында кеңейту әдістері өздеріне пайдалы үлгілерді де қосады. Кеңейту әдістерін енгізудің негізгі себебі болды Тілдің интеграцияланған сұрауы (LINQ). Кеңейту әдістерін компиляторлық қолдау жаңа кодпен бірдей ескі кодпен LINQ-ті терең интеграциялауға, сондай-ақ сұраным синтаксисі бір сәтте тек бастапқыға ғана тән Microsoft .NET тілдер.

Консоль.WriteLine(жаңа[] { Математика.PI, Математика.E }.Қайда(г. => г. > 3).Таңдаңыз(г. => Математика.Күнә(г. / 2)).Қосынды());// Шығарылым:// 1

Жалпы мінез-құлықты орталықтандырыңыз

Алайда кеңейту әдістері мүмкіндіктерді қайта-қайта қажет етпейтін тәсілдермен бір рет іске асыруға мүмкіндік береді мұрагерлік немесе үстеме шығындар виртуалды әдіс шақырулар немесе орындалушылардың орындалуын талап етеді интерфейс маңызды емес немесе күрделі функционалдылықты жүзеге асыру.

Ерекше пайдалы сценарий, егер функция интерфейсте жұмыс жасаса немесе нақты іске асырылмаған болса немесе сынып кітапханасының авторы пайдалы іске асыруды қамтамасыз етпесе, мысалы. көбінесе плагин архитектурасын немесе соған ұқсас функционалды әзірлеушілерді қамтамасыз ететін кітапханаларда жиі кездеседі.

Келесі кодты қарастырыңыз және ол класс кітапханасындағы жалғыз код деп есептеңіз. Дегенмен, ILogger интерфейсінің кез-келген орындаушысы форматталған жолды жазу мүмкіндігіне ие болады MyCoolLogger көмегімен өтініш, оны бір рет енгізбестен және сынып кітапханасының ішкі сыныбын талап етпестен ILogger бағдарламасын енгізуді қамтамасыз етеді.

аттар кеңістігі MyCoolLogger {    қоғамдық интерфейс ILogger { жарамсыз Жазыңыз(жіп мәтін); }    қоғамдық статикалық сынып LoggerExtensions {        қоғамдық статикалық жарамсыз Жазыңыз(бұл ILogger ағаш кесуші, жіп формат, парам объект[] доға) {             егер (ағаш кесуші != нөл)                ағаш кесуші.Жазыңыз(жіп.Пішім(формат, доға));        }    }}
  • келесідей пайдалану:
    var ағаш кесуші = жаңа MyLoggerImplementation();ағаш кесуші.Жазыңыз("{0}: {1}", «kiddo sais», «Мам мам мам мам мам ...»);ағаш кесуші.Жазыңыз("{0}: {1}", «kiddo sais», «Ма ма ма ма ...»);ағаш кесуші.Жазыңыз("{0}: {1}", «kiddo sais», «Мама мама мама мама»);ағаш кесуші.Жазыңыз("{0}: {1}", «kiddo sais», «Мамма мамма мамма ...»);ағаш кесуші.Жазыңыз("{0}: {1}", «kiddo sais», «Элизабет Лиззи Лиз ...»);ағаш кесуші.Жазыңыз("{0}: {1}", «mamma sais», «НЕ?!?!!!»);ағаш кесуші.Жазыңыз("{0}: {1}", «kiddo sais», «сәлем».);

Іліністі ілінісу

Кеңейту әдістері сынып кітапханаларының пайдаланушыларына аргумент, айнымалы немесе басқа түрдегі кітапханадан шығатын нәрсені жариялаудан бас тартуға мүмкіндік береді. Сынып кітапханасында қолданылатын типтерді құру және түрлендіру кеңейту әдісі ретінде жүзеге асырылуы мүмкін. Түрлендірулер мен зауыттарды мұқият іске асырғаннан кейін, сыныптың кітапханасынан екіншісіне ауысуды компилятор үшін кеңейту әдістерін қол жетімді ететін пайдалану операторын өзгерту сияқты жеңілдетуге болады.

Бағдарламалаушының еркін интерфейстері

Кеңейту әдістері еркін интерфейстер деп аталатын бағдарламаларды іске асыруда ерекше қолданылады. Мысал ретінде Microsoft корпорациясының Entity Framework конфигурациясының API-сін алуға болады, мысалы, кәдімгі ағылшын тіліне ұқсас код жазуға мүмкіндік береді.

Мұны кеңейту әдістерінсіз де мүмкін деп айтуға болады, бірақ іс жүзінде кеңейту әдістері жоғары тәжірибе ұсынады, себебі оны сынып иерархиясында қалауынша жұмыс жасау және оқу үшін аз шектеулер қойылады.

Келесі мысал Entity Framework-ті пайдаланады және TodoList сыныбын мәліметтер қорының кестесінде сақтау үшін конфигурациялайды, бастапқы және сыртқы кілттерді анықтайды. Кодты азды-көпті түсіну керек: «TodoList-те TodoListID кілті бар, оның жиынтық атауы - Тізімдер және оның әрқайсысында қажетті TodoList бар көптеген TodoItem бар».

қоғамдық сынып TodoItemContext : DbContext {    қоғамдық DbSet<TodoItem> TodoItems { алу; орнатылды; }    қоғамдық DbSet<Тізім жасау> TodoLists { алу; орнатылды; }    қорғалған жоққа шығару жарамсыз OnModelCreating(DbModelBuilder modelBuilder)     {        негіз.OnModelCreating(modelBuilder);        modelBuilder.Субъект<Тізім жасау>()                    .HasKey(e => e.TodoListId)                    .HasEntitySetName(«Тізімдер»)                    .HasMany(e => e.Todos)                    .Қажет(e => e.Тізім жасау);    }}

Өнімділік

Мысалы, қарастырайық IEnumerable және оның қарапайымдылығына назар аударыңыз - бір ғана әдіс бар, бірақ бұл LINQ-тің негізі азды-көпті. Microsoft .NET-те бұл интерфейстің көптеген нұсқалары бар. Алайда, әрине, осы іске асырулардың әрқайсысында анықталған барлық әдістер тізбегін жүзеге асыруды талап ету қиын болатын еді. System.Linq аттар кеңістігі Майкрософтта барлық бастапқы кодтар болса да, IEnumerables-да жұмыс істеу керек. Одан да сорақысы, бұл Microsoft корпорациясынан басқа бәріне IEnumerable-ді қолдануды қажет ететін әдістердің барлығын қолдануды талап етуі керек еді, бұл өте кең таралған интерфейстің кең қолданылуын көргенде нәтижеге қарсы болатын еді. Керісінше, осы интерфейстің бір әдісін қолдану арқылы LINQ-ны бірден немесе аз мөлшерде қолдануға болады. IEnumerable GetEnumerator әдісін іс жүзінде көп жағдайда көру жеке коллекцияға, тізімге немесе массивтің GetEnumerator енгізілуіне беріледі.

қоғамдық сынып Банк шоты : IEnumerable<ондық> {    жеке Тізім<Тупле<DateTime, ондық>> несиелер; // барлық жағымсыз деп қабылдады    жеке Тізім<Тупле<DateTime, ондық>> дебет; // барлық оң деп қабылдады    қоғамдық INumerator<ондық> GetEnumerator()     {        var сұрау = бастап dc жылы дебет.Одақ(несиелер)                     бойынша сұрыптау dc.1-тармақ / * Күні * /                     таңдаңыз dc.2-тармақ; / * Сома * /            әрқайсысы үшін (var сома жылы сұрау)            Өткізіп жібер қайту сома;    }}// BankAccount ба деп аталатын данасы және ағымдағы файлдың жоғарғы жағында System.Linq пайдалану берілген,// енді шоттағы қалдықты алу үшін ba.Sum (), ең соңғы транзакцияларды алдымен көру үшін ba.Reverse () жазуға болады,// ba.Average () транзакцияға орташа соманы алу үшін және т.с.с. - арифметикалық операторды ешқашан жазбай

Өнімділік

Айтуынша, өнімділікті жақсарту үшін немесе компиляторға IEnumerable массивтері үшін арнайы іске асыруды қамтамасыз ету сияқты интерфейс енгізілімдерімен айналысу үшін кеңейту әдісімен ұсынылатын мүмкіндіктің қосымша орындалуын қосуға болады (System.SZArrayHelper ішінде) массив терілген сілтемелерді кеңейту әдісі үшін шақыруды автоматты түрде таңдайды, өйткені олардың дәлелі IEnumerable интерфейсінің даналарында жұмыс жасайтын кеңейту әдісіне қарағанда нақтырақ (бұл T [] мәні) болады (бұл IEnumerable мәні).

Жалпы базалық кластың қажеттілігін жеңілдету

Жалпы кластармен кеңейту әдістері жалпы типтегі барлық инстанциялар үшін қол жетімді мінез-құлықты жүзеге асыруға мүмкіндік береді, олардың жалпы базалық класстан шығуын талап етпей және типтің параметрлерін белгілі бір мұрагерлік тармақпен шектемей. Бұл үлкен жеңіс, өйткені бұл аргумент жағдайлары ортақ функцияны жүзеге асыру үшін жалпы емес класс класын қажет етеді, содан кейін жалпы подкласс бокспен айналысуды қажет етеді және / немесе тип қолданылатын аргументтердің әрқайсысы болған кезде шығарады. .

Консервативті қолдану

Кеңейту әдістерін қайта пайдалануға және объектіге бағытталған дизайнға қол жеткізудің басқа әдістеріне қарағанда артықшылық беру керек. Кеңейту әдістері Visual Studio-ның IntelliSense сияқты код редакторларының автоматты түрде аяқталу мүмкіндіктерін «бұзуы» мүмкін, сондықтан олар өздерінің ат кеңістігінде болуы керек. әзірлеушіге оларды іріктеп импорттауға мүмкіндік беру немесе оларды IntelliSense-те әдістің пайда болуы үшін жеткілікті нақты типте анықтау қажет және жоғарыда айтылғандарды ескере отырып, әзірлеуші ​​күткен жағдайда оларды табу қиын болуы мүмкін деп ойлаңыз, бірақ оларды IntelliSense-тен жіберіп алғандығымен байланысты жіберіп алғандығына байланысты жіберіп алыңыз, өйткені әзірлеуші ​​әдісті оны анықтайтын сыныппен, тіпті ол өмір сүретін аттар кеңістігімен байланыстырмаған болуы мүмкін, керісінше ол кеңейтілетін типпен және сол типтегі аттар кеңістігімен байланысты болуы мүмкін өмір сүреді.

Мәселесі

Бағдарламалау кезінде бар класқа функционалдылықты қосу қажет болатын жағдайлар туындайды, мысалы, жаңа әдісті қосу арқылы. Әдетте бағдарламашы бар класты өзгертеді бастапқы код, бірақ бұл бағдарламашыны мәжбүр етеді қайта құрастыру барлық екілік файлдар осы жаңа өзгерістермен және бағдарламашының сыныпты өзгерте алуын талап етеді, бұл әрдайым мүмкін емес, мысалы, үшінші тараптың сыныптарын пайдалану кезінде құрастыру. Бұл әдетте үш тәсілдің бірімен жұмыс істейді, олардың барлығы шектеулі және түсініксіз[дәйексөз қажет ]:

  1. Сыныпты мұрагерлеңіз, содан кейін функцияны туынды сыныпта даналық әдіске енгізіңіз.
  2. Функционалдылықты көмекші классқа қосылған статикалық әдіспен іске асырыңыз.
  3. Пайдаланыңыз жинақтау орнына мұрагерлік.

Ағымдағы C # шешімдері

Бірінші нұсқа негізінен оңайырақ, бірақ, өкінішке орай, көптеген сыныптар белгілі бір мүшелердің мұрагерлігін шектейтіндігімен немесе оған толықтай тыйым салатындығымен шектеледі. Бұған мөр басылған сынып және C # типіндегі әртүрлі қарабайыр деректер түрлері жатады int, жүзу және жіп. Екінші нұсқа, екінші жағынан, бұл шектеулерді бөліспейді, бірақ бұл интуитивті болмауы мүмкін, себебі ол қарастырылып отырған сыныптың әдістерін тікелей қолданудың орнына бөлек сыныпқа сілтеме жасауды қажет етеді.

Мысал ретінде жол классын жаңа кері әдіспен кеңейту қажеттілігін қарастырайық, оның қайтару мәні символдары кері тәртіпте болатын жол. Жолдар класы мөрленген тип болғандықтан, әдіс жаңаға қосылады утилита сыныбы келесідей тәсілмен:

жіп х = «кейбір жол мәні»;жіп ж = Утилита.Кері(х);

Алайда, бұны навигациялау қиындай түсуі мүмкін, өйткені коммуналдық әдістер мен сыныптардың кітапханасы көбейеді, әсіресе жаңадан келгендер үшін. Орналасуы да интуитивті емес, өйткені көптеген жолдық әдістерден айырмашылығы, ол жолдар класының мүшесі болмай, мүлде басқа класста болады. Жақсырақ синтаксис келесідей болуы мүмкін:

жіп х = «кейбір жол мәні»;жіп ж = х.Кері();

Қазіргі VB.NET шешімдері

Көп жағдайда VB.NET шешімі жоғарыдағы C # шешіміне ұқсас. Алайда VB.NET-тің бірегей артықшылығы бар, өйткені ол мүшелерді кеңейтуге сілтеме арқылы өтуге мүмкіндік береді (C # тек мәні бойынша мүмкіндік береді). Келесіге рұқсат беру;

Күңгірт х Қалай Жол = «кейбір жол мәні»х.Кері()

Visual Basic бастапқы объектіні сілтеме арқылы қабылдауға мүмкіндік беретіндіктен, басқа айнымалыны құрудың қажеті жоқ, бастапқы объектіге тікелей өзгертулер енгізуге болады. Бұл сонымен қатар интуитивті, өйткені сабақтардың қолданыстағы әдістеріне сәйкес келеді.

Кеңейту әдістері

C # 3.0 кеңейту әдістерінің жаңа тілдік ерекшелігі, соңғы кодты мүмкін етеді. Бұл тәсіл келесідей статикалық класс пен статикалық әдісті қажет етеді.

қоғамдық статикалық сынып Утилита{    қоғамдық статикалық жіп Кері(бұл жіп енгізу)    {        char[] белгілер = енгізу.ToCharArray();        Массив.Кері(белгілер);        қайту жаңа Жол(белгілер);    }}

Анықтамада бірінші аргументтің алдындағы 'this' модификаторы оның кеңейту әдісі екенін көрсетеді (бұл жағдайда 'string' түріне). Қоңырау кезінде бірінші аргумент «жіберілмейді», өйткені ол қазірдің өзінде «шақырушы» объект (нүкте алдындағы объект) ретінде белгілі.

Кеңейту әдістерін шақырудың статикалық көмекші әдістерін шақырудан басты айырмашылығы - статикалық әдістер шақырылады префикстің белгісі, ал кеңейту әдістері шақырылады инфикс белгісі. Соңғысы бір операцияның нәтижесі басқа операцияға қолданылған кезде оқылатын кодқа әкеледі.

Статикалық әдістермен
HelperClass.Операция2(HelperClass.Пайдалану(х, арг1), арг2)
Кеңейту әдістерімен
х.Пайдалану(арг1).Операция2(арг2)

Кеңейту әдістері мен даналық әдістердегі қайшылықтарды атау

C # 3.0-де экземпляр әдісі де, бірдей қолтаңбасы бар кеңейту әдісі де класс үшін бола алады. Мұндай сценарийде кеңейту әдісінен гөрі даналық әдіске артықшылық беріледі. Компилятор да, Microsoft Visual Studio IDE ат қою жанжалы туралы ескертеді. Осы C # сыныбын қарастырайық, мұндағы GetAlphabet () әдіс осы сыныптың данасында шақырылады:

сынып AlphabetMaker {    қоғамдық жарамсыз GetAlphabet()           {                               // Бұл әдіс жүзеге асырылған кезде,        Консоль.WriteLine(«abc»);   // бұл іске асыруды көлеңкелендіреді    }                               // ExtensionMethods класында.}статикалық сынып Кеңейту әдістері{    қоғамдық статикалық жарамсыз GetAlphabet(бұл AlphabetMaker мен)       {                               // Бұл тек шақырылатын болады         Консоль.WriteLine(«ABC»);   // егер данасы болмаса    }                               // бірдей қолтаңба қойылған әдіс. }

Шақыру нәтижесі GetAlphabet () данасында AlphabetMaker егер тек кеңейту әдісі болса:

ABC

Егер инстанция әдісі де, кеңейту әдісі де болса:

abc

Сондай-ақ қараңыз

Әдебиеттер тізімі

  1. ^ «Кеңейту әдістері». Microsoft. Алынған 2008-11-23.

Сыртқы сілтемелер