Sunt delegații nu doar interfețe de stenografie?

Să presupunem că avem:

interface Foo 
{
 bool Func(int x);
}

class Bar: Foo
{
  bool Func(int x)
  {
   return (x>0);
  }  
}

class Baz: Foo
{
  bool Func(int x)
  {
   return (x<0);
  }  
}

Acum putem arunca Barul și Bazul ca Foos și numim metodele lor Func.

Delegații simplifică acest lucru:

delegate bool Foo(int x);

bool Bar(int x)
{
 return (x<0);
}

bool Baz(int x)
{
 return (x>0);
}

Acum putem să-i aruncăm pe Bar și Baz ca pe delegații Foo.

Care este beneficiul real al delegațiilor, cu excepția primirii unui cod mai scurt?

0

10 răspunsuri

Nu, delegații sunt pentru indicatorii de metode. Apoi, puteți să vă asigurați că semnătura metodei asociate cu delegatul este corectă.

De asemenea, atunci nu trebuie să cunoașteți structura clasei. În acest fel, puteți utiliza o metodă pe care ați scris-o pentru a trece într-o metodă dintr-o altă clasă și pentru a defini funcționalitatea pe care doriți să o întâlniți.

Take a look at the List<> class with the Find method. Now you get to define what determines if something is a match or not, without requiring items contained in the class to implement IListFindable or something similar.

0
adăugat

Un delegat este un indicator al metodei tastate. Acest lucru vă oferă mai multă flexibilitate decât interfețele deoarece puteți profita de covarianță și contravariență și puteți modifica starea obiectului (va trebui să treceți acest pointer în jurul valorii de functorii bazați pe interfață).

De asemenea, delegații au multe zahăr sintactic, care vă permit să faceți lucruri cum ar fi combinarea acestora cu ușurință.

0
adăugat

În cel puțin o propunere de adăugare a închiderilor (adică delegați anonimi) către Java, acestea sunt echivalente cu interfețele cu o singură metodă a membrilor.

0
adăugat

Se poate gândi la delegați ca o interfață pentru o metodă care definește argumentele și tipul de retur care trebuie să aibă o metodă pentru a se potrivi cu delegatul

0
adăugat

Un delegat împărtășește multe în comun cu o referință de interfață care are o singură metodă din punctul de vedere al apelantului.

În primul exemplu, Baz și Bar sunt clase, care pot fi moștenite și instanțiate. În al doilea exemplu, Baz și Bar sunt metode.

Nu puteți aplica referințe de interfață la orice clasă care se potrivește cu contractul de interfață. Clasa trebuie să declare în mod explicit că suportă interfața. Puteți aplica o referință de delegat la orice metodă care se potrivește cu semnătura.

Nu puteți include metode statice într-un contract de interfață. (Deși puteți utiliza metode statice cu metode de extensie). Puteți consulta metode statice cu o referință de delegat.

0
adăugat

Puteți delega delegați ca parametri în funcții (OK, delegații tehnici devin obiecte atunci când sunt compilate, dar acest lucru nu este punctul aici). Ați putea să transmiteți un obiect ca parametru (evident), dar atunci legați acest tip de obiect funcției ca parametru. Cu delegați puteți trece orice funcție pe care să o executați în codul care are aceeași semnătură, indiferent de unde provine.

0
adăugat

Da, un delegat poate fi considerat ca o interfață cu o metodă.

0
adăugat

Există o mică diferență, delegații pot accesa variabilele membre ale claselor în care sunt definite. În C# (spre deosebire de Java), toate clasele interioare sunt considerate statice. Prin urmare, dacă utilizați o interfață pentru gestionarea unui apel invers, de ex. un ActionListener pentru un buton. Clasa interioară de implementare trebuie să fie transmisă (prin constructor) referințe la părțile din clasa de conținut care ar putea fi necesar să interacționeze în timpul apelului invers. Delegătorii nu au această restricție, prin urmare, reduc cantitatea de cod necesară pentru implementarea callback-ului.

Codul mai scurt, mai concis este, de asemenea, un beneficiu demn.

0
adăugat
Nu sunt doar variabile membre. Sunt chiar variabile locale sau parametri ai metodei în care este definit un delegat anonim.
adăugat autor Daniel Earwicker, sursa
@supercat Corect. Dar de ce credeți că interfețele vor "funcționa mai bine" decât delegații? Un delegat este logic același lucru ca o interfață cu o singură metodă.
adăugat autor Daniel Earwicker, sursa
(1) "cazuri de heap" nu sunt deosebit de costisitoare în CLR. Vedeți smellegantcode.wordpress. com/2009/03/01/& hellip; (2) Ce este în neregulă cu delegate void MyDelegate (T v) unde T: IFoo, IBar;
adăugat autor Daniel Earwicker, sursa
adăugat autor Daniel Earwicker, sursa
@DanielEarwicker: O rutină în care o închidere este definită definește o clasă de „ascunse“ speciale pentru a ține variabile locale, creează o instanță a unei astfel de clasă în orice moment aceste variabile intră domeniul de aplicare, și utilizează câmpurile din acea clasă în loc de „normale“ locale variabile. Scenariile care utilizează închiderile ar funcționa mai bine cu interfețele decât cu delegațiile.
adăugat autor supercat, sursa
@DanielEarwicker: Cel puțin două motive: (1) Să presupunem că o rutină va apela un Action într-o anumită situație și în această situație vreau să apeleze Foo (x) cu valoarea curentă a variabilei locale x . Trimiterea unei astfel de solicitări ca delegat necesită crearea a două instanțe de heap: un obiect temporar de clasă care să dețină x și un delegat să îl numească. Transmiterea cererii ca tip de interfață ar necesita crearea unei instanțe de heap (o implementare a interfeței). Trecerea acestuia ca generic constrâns de interfață ar putea să
adăugat autor supercat, sursa
(2) Interfețele pot avea metode generice deschise, în timp ce delegații nu pot. Să presupunem că am o colecție de obiecte care nu au un tip de bază comun, dar toate sunt de tip constrâns să implementeze IFoo și IBar. Aș dori să pot rula o rutină externă furnizată, care ia un parametru limitat la IFoo și IBar. Nu există nici o modalitate de a specifica faptul că un delegat are un parametru de tipul T: IFoo, IBar , dar este posibil să se declare o metodă de interfață care face acest lucru.
adăugat autor supercat, sursa
@DanielEarwicker: Problema cu aceasta este că rutina care creează delegatul trebuie să specifice tipul T . Să presupunem că o clasă are o colecție de obiecte care toate implementează I1 și I2 , dar nu au un tip de bază comun care implementează ambele; dorește să expună o metodă ForAll . Dacă o astfel de metodă a acceptat un obiect de tip interfață IActUponConstrained {void Act (T param) unde T: I1, I2;} T> pentru fiecare element fără entitatea care a creat IActUponConstrained ca
adăugat autor supercat, sursa
@DanielEarwicker: Dacă nu doriți să utilizați Reflecția, interfața generică este necesară deoarece parametrii generici de tastare pot muta doar "în jos" (mai adânc în) stiva de apeluri. O colecție de clasă abstractă ThingImplementing poate conține instanțe ale claselor derivate ThingImplementing .WithType unde ActualType: I1, I2 . Fiecare instanță este legată de tipul generic cu care a fost creat, dar dacă alt cod va fi apelat utilizând acel parametru de tip, instanța va trebui să facă apelul propriu-zis. Dacă Foo și
adăugat autor supercat, sursa
... ambele interfețe, nu există nici o modalitate de a defini un delegat cu un parametru de tip constrâns atât la I1 , cât și la I2 , la care ThingImplementing .Type ar putea să treacă un Foo și la care ThingImplementing .WithType . Cu toate acestea, putem defini o implementare a IActUponConstrained , trecem la ambele obiecte și avem primul Act (Foo param) al doilea apel Act (Bar param) .
adăugat autor supercat, sursa
@DanielEarwicker: Exact. Abilitatea de a avea un tip de interfață de tip consumator oferă un parametru de tip generic este diferit de tot ce se poate face cu delegații .net. De fapt, nu sunt sigur că va exista o necesitate reală pentru delegați în cadru dacă compilatorii ar putea face pentru interfețe generice câteva dintre lucrurile pe care le fac pentru delegați (de exemplu, având o interfață cu un Invocați metoda care are o anumită semnătură, construiește o clasă a cărei constructor ia două implementări ale acelei interfețe și care implementează invocând apelând ambele instan
adăugat autor supercat, sursa
... generice nu au existat în .net 1.0, deci delegații cvasi-generici au reprezentat un obstacol necesar. De altfel, mă întreb de ce derivatele generate de compilatorul Delegate nu definesc propriile metode Combine și Remove>/code> specifice? Astfel de metode pot funcționa corespunzător cu tipuri de delegați contravarianți, în timp ce Delegate.Combine nu pot.
adăugat autor supercat, sursa
Este interesant de remarcat faptul că delegații pot avea acces la membri. O metodă înfășurată în clasă, care poate fi trecută, ar putea acționa cu ușurință ca un curier pentru datele obținute, dar accesul direct este un mod mult mai rapid de a face acest lucru.
adăugat autor Rick Minerich, sursa

Din perspectiva ingineriei software, ai dreptate, delegații se aseamănă mult cu interfețele funcționale prin faptul că prototip o interfață de funcții.

Ele pot fi de asemenea folosite mult în același fel: în loc să treci o clasă întreagă în care conține metoda de care ai nevoie, poți trece în doar un delegat. Aceasta salvează o mulțime de coduri și creează un cod mult mai ușor de citit.

Mai mult, odată cu apariția expresiilor lambda, ele pot fi acum definite, de asemenea, cu ușurință în zbor, ceea ce reprezintă un bonus imens. În timp ce este posibil de a construi clase în zbor în C#, este într-adevăr o mare durere în fund.

Compararea celor două este un concept interesant. Nu m-am gândit anterior cât de mult sunt ideile dintr-un caz de utilizare și un punct de structurare a codului.

0
adăugat

Interfețele și delegații sunt două lucruri complet diferite, deși înțeleg tentația de a descrie delegații în termeni asemănători interfeței pentru a fi ușor de înțeles ... totuși, neștiind adevărul poate duce la confuzie pe linie.

Delegații au fost inspirați (parțial) din cauza faptului că arta neagră a metodelor C ++ este inadecvată pentru anumite scopuri. Un exemplu clasic este implementarea unui mecanism de trecere a mesajelor sau de gestionare a evenimentelor. Delegații vă permit să definiți o semnătură de metodă fără a cunoaște tipurile sau interfețele unei clase - aș putea defini un "void eventHandler (Event * e)" și să îl invocați pe orice clasă care a implementat-o.

Pentru o scurtă prezentare a acestei probleme clasice și de ce este de dorit delegații, citiți acest lucru și apoi acest .

0
adăugat