Delegates
Sortering
Merk at dette ikke er noen oppskrift på effektiv sortering. Vitsen er bare å finne et enkelt eksempel der bruken av delegates er tydelig.
Koden i Form1 er slik:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace delegate1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } // a delegate public delegate bool Compare(string e1, string e2); // sorting by bubbling // Parameter: // a list // a delegate with a method for comparing elements public static void bubble(String[] wlist, Compare cmp) { bool isOk; do { isOk = true; for (int ix = 0; ix < wlist.Length - 1; ix++) if(cmp(wlist[ix],wlist[ix+1])) { string tmp = wlist[ix]; wlist[ix] = wlist[ix + 1]; wlist[ix + 1] = tmp; isOk = false; } } while (!isOk); } // the two functions we will send with the delegate private bool SortAscending(string s1, string s2) {return s1.CompareTo(s2) > 0;} private bool SortDescending(string s1, string s2) {return s1.CompareTo(s2) < 0;} // show result private void Display(String[] wlist) { listBox1.Items.Clear(); listBox1.Items.AddRange(wlist); } // intiating the wordlist private void Form1_Load(object sender, EventArgs e) { textBox1.Text = @"en demonstrasjon av delegates"; Display(textBox1.Text.Trim().Split(' ')); } // when we want alphabetic order private void buttonAscending_Click(object sender, EventArgs e) { String[] wlist = textBox1.Text.Trim().Split(' '); bubble(wlist, new Compare(SortAscending)); Display(wlist); } // when we want reverse alphabetic order private void buttonDescending_Click(object sender, EventArgs e) { String[] wlist = textBox1.Text.Trim().Split(' '); bubble(wlist, new Compare(SortDescending)); Display(wlist); } } }
Eventhandlere
Det å fange opp begivenheter, events, er en typisk problemstilling i f.eks. all GUI-programmering, og forskjellige språk og forskjellige plattformer har opp gjennom årene hatt forskjellige løsninger på dette. Problemstillingen er i korthet slik:
Vårt program skal respondere på en begivenhet som vi ikke vet når intreffer, og vi ønsker å spesifisere en metode som kan handtere begivenheten. La oss ta et museklikk som eksempel. Museklikket registreres av operativsystemet og legges i en kø av begivenheter som skal behandles. Når vårt museklikk kommer først i denne køen, rutes det til det programmet som har fokus, vårt program. Så er det opp til vårt program hvor ansvaret for å respondere på begiveheten skal plasseres, og hva som skal gjøres.
En prinsippskisse for Windows kan se slik ut:

Metoden WinMain ligger i bakgrunnen og tar imot alle meldinger som er rutet til vårt program. Så fordeles disse til de respektive vinduene, GUI-komponentene. I de tidligste versjoene av Windows var denne mekanismen eksplisitt og som programmerer måtte du lage generelle metoder for å handtere begivenheter. Disse metodene måtte "eksporteres" som entrypunkter til operativsystemet, altså som adresser til behandlingsfunksjoner. Innmaten i disse behandlingsmetodene besto stort sett av en switch med et case for de begivenhetene vi var interesserte i, av og til omtalt som: "The Long Switch". Hvis du vil ha en liten smak av hvordan det kunne se ut kan du se på kildekoden til et enkelt c-program som tegner ut røde prikker i et vindu: cdots.c og cdots.h
I dagens systemer trenger vi ikke ta et slikt helhetsansvar. Vi kan nøye oss med å angi metoder for hver begivenhet, for hver GUI-komponent. Og bare de begivenhetene vi ønsker å respondere på. De begivenetene vi ikke er intteresserte i blir behandlet på en standard måte. Hva som er standard eller default avhenger av typen GUI-komponent. F.eks. trenger vi vanligvis ikke skrive noen metode for å flytte fokus til en komponent vi klikker på. Vi trenger heller ikke skrive noen metode for at tegn vi skriver i et inputfelt skal legges til teksten.
Vi kan se på et enkelt eksempel. Når vi designer et GUI i Visual Stdio og tilordner en behandlingsfunksjon for en begivenhet, generer GUI-editoren en kodebit som kan se slik ut, for et ComboBox-object, myBox:
this.myBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.myBox.FormattingEnabled = true; this.myBox.Location = new System.Drawing.Point(11, 150); this.myBox.Name = "comboBoxView"; this.myBox.Size = new System.Drawing.Size(174, 21); this.myBox.TabIndex = 3; this.myBox.SelectedIndexChanged += new System.EventHandler(this.myBox_SelectedIndexChanged);
Det er den siste linja som er interessant for vårt resonnement. SelectedIndexChanged er et EventHandler-objekt. new System.EventHandler skaper en ny delegate som blir lagt til de som eventuelt måtte være i SelectedIndexChanged fra før. Parameteren til konstrukøren er en funksjon som vi må skrive: myBox_SelectedIndexChanged.
I Java er begrepet Listener sentralt i å implementere tilsverende mekanismer. Javacode som tilordner en metode til en begivenhet kan se slik ut:
myBox.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { myBoxItemStateChanged(evt); } });
Her har vi brukt teknikken med å tilordne en anonym ItemListener. Koden vi må skrive er : myBoxItemStateChanged.
"gjør det selv"
I stedet for å overlate til GUI-editoren å lage kode for oss kan vi gjøre det selv. Ulempene er selvsagt at vi må håndkode alle properties i komponentene, alle posisjoner etc. Men muligheten for en annen programarkitektur enn den GUI-designeren inviterer til er tilstede. Et enkelt eksempel. Koden nedenfor er all koden i en consoleapplikasjon som skaper og vedlikeholder sin egen form:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace ownWindow { public class myForm : Form { private static bool done = false; public myForm() { // delegating this.Closing += new CancelEventHandler(this.Form_Closing); this.Resize += new EventHandler(this.Form_Resize); this.Paint += new PaintEventHandler(this.Form1_Paint); } private void Form_Closing(object sender, CancelEventArgs e) { done = true; } private void Form1_Paint(object sender, PaintEventArgs e) { e.Graphics.DrawString(String.Format(@"{0} X {1} pixels", this.Width, this.Height), new Font(this.Font, FontStyle.Bold), new SolidBrush(Color.Black), new Point(20, 20)); } private void Form_Resize(object sender, EventArgs e) { this.Invalidate(); } } class Program { private static bool done = false; static void Main(string[] args) { myForm form = new myForm(); form.SetBounds(100, 100, 300, 300); form.FormBorderStyle = FormBorderStyle.Sizable; form.Text = "Show size"; // show the form form.Show(); // main loop while (!done) { Application.DoEvents(); } // take form down if (form != null) { form.Hide(); form.Close(); form = null; Application.Exit(); } } } }
Predicates
Her brukt som søkefilter.
Vi bygger en enkel applikasjon med en liste av personer. Dataene er basert på en textressurs: dataPredicate.txt, og personklassen er beskrevet slik:
Vi lager en Form-application med to lister og en button med følgende kode:

Den interessante koden er kallet på pList.FindAll() med en metode, haldenser, som parameter. Vi må lese dette slik at vi ber metoden FindAll å bruke en delegate til å filtrere hva som skal brukes. Det finnes flere varianter av dette. Sjekk hva List-klassen har for slags funksjonalitet.
En variant
Vi bruker de samme dataene og beholder klassen person. Vi gjør to endringer. For det førtse putter vi flere typer objekter inn i lista, for det andre lager vi liste2 basert på liste1.