2009-08-04 9 views
0

Angenommen ich folgende Delegierte habenAngeben Arttypisch eines Delegierten Argument

public delegate void ControlInitializer(Control control); 

Gibt es eine Möglichkeit, wenn die Angabe des Delegaten angeben, welche Art der Steuerung der Eingangsparameter ist? z.B.

Statt

ControlInitializer one = c => ((TextBox)c).Text = "Init Value" 
ControlInitializer two = c => ((DropDownList)c).SelectedValue= "-1" 

Kann ich etwas tun, wie

ControlInitializer one = (TextBox c) => c.Text = "Init Value" 
ControlInitializer two = (DropDownList c) => c.SelectedValue= "-1" 

Als Textbox eine Unterklasse der Steuerung ist in diesem Fall?

Update: Ich muss diese 2 ControlInitialiser Delegaten auch in einem z.

Dictionary<string, ControlInitializer> 

wird die Angabe

Dictionary<string, ControlInitializer<Control>> 

Die Arbeit in diesem Fall, wie ich kann nicht scheinen, um zu arbeiten.

Vielen Dank im Voraus.

+1

Sie Aktion verwenden können stattdessen Ihre eigenen Delegaten definieren, wenn Sie .NET Framework 3.5 verwenden. –

+1

'Aktion ' ist in .net 2.0 sowie –

Antwort

10

Sie die Delegaten generic machen kann:

public delegate void ControlInitializer<TControl>(TControl control) 
    where TControl : Control; 

Und es dann wie folgt verwenden:

ControlInitializer<TextBox>  one = c => c.Text = "Init Value"; 
ControlInitializer<DropDownList> two = c => c.SelectedValue = "-1"; 

ich Sich für so etwas wie dieses Ziel erraten:

var init = new Init(); 

init.RegisterInitializer<TextBox>(c => c.Text = "Init Value"); 
init.RegisterInitializer<DropDownList>(c => c.SelectValue = "-1"); 

foreach (var c in Controls) 
{ 
    init.ApplyInitializer(c); 
} 

Das ist ein bisschen schwierig wegen der r Easons erwähnt in David B 's Antwort. Was Sie tun können, ist jedoch die Art hinter einer Abstraktion, wie diese werfen verstecken:

public class Init 
{ 
    private readonly Dictionary<Type, Action<Control>> initializers; 
    ... 

    public void RegisterInitializer<TControl>(Action<TControl> i) 
     where T Control : Control 
    { 
     initializers.Add(typeof(TControl), c => i((TControl)c)); 
    } 

    public void ApplyInitializer(Control c) 
    { 
     initializers[c.GetType()](c); 
    } 
} 
+0

Sounds gut. Wenn ich einen Dictionary habe, der diese in einer statischen Variablen speichert, kann ich ihn mit Dictionary > initialisieren und Delegaten "eins" und "zwei" hinzufügen? –

+0

Nein, wegen Typ Kovarianz –

3

Zunächst einmal, verwenden Sie die vordefinierten Delegierten Action. Hinsichtlich der Art anzugeben, verwenden Sie generische Argumente:

Action<TextBox, string> one = (c,v) => c.Text = v; 

Der Action Delegierte bis zu 4 Argumente nimmt und nichts zurückgibt (void).

+0

Ich realisiere dies, aber dieses Beispiel ist eine leichte Abstraktion und Aktion würde nicht für die reale Sache gelten. –

+0

dann gibt es immer 'Prädikat' und 3.5's' Func' –

2

Sie können keine zu einem ControlInitializer<TextBox> zu einem Wörterbuch hinzufügen, die ControlInitializer<Control>weil der erste Typ von der zweiten Art (auch wenn TextBox erbt von Control.) Nicht erbt Es ist alles über den Mangel an Kovarianz und Kontra hält in Generika.

Sie könnten Ihre eigene Sammlung schreiben, um sich so zu verhalten, wie Sie es erwarten.Hier ist eine Möglichkeit:

public class CustomStorage 
{ 
    private Dictionary<string, object> storage = new Dictionary<string, object>(); 

    public void Remember(string key, object value) 
    { 
    storage[key] = value; 
    } 

    public object Retrieve(string key) 
    { 
    object x = storage[key]; 
    return x; 
    } 

    public U Retrieve<U>(string key) 
    { 
    U u = (U) storage[key]; 
    return u; 
    } 
} 

, welche diese Art und Weise verwendet werden könnten:

CustomStorage cs = new CustomStorage(); 
ControlInitializer<TextBox> one = c => c.Text = "Init Value"; 
ControlInitializer<DropDownList> two = c => c.SelectedValue = "-1"; 
    //drop the items into the collection ... 
cs.remember("TextBox", one); 
cs.remember("DropDownList", two); 
    // ... and fetch them back 
one = cs.Retrieve<ControlInitializer<TextBox>>("TextBox"); 
two = cs.Retrieve<ControlInitializer<DropDownList>>("DropDownList"); 
+0

Wird es möglich sein, dies in .Net 4.0 zu erreichen, was Co- und Kontravarianzen einführt? – Giorgi