2009-08-04 5 views
0

En supposant que je le délégué à la suiteSpécification du type spécifique d'un délégué Argument

public delegate void ControlInitializer(Control control); 

est-il un moyen pour spécifier le délégué de préciser quel type de contrôle du paramètre d'entrée est? par exemple.

Au lieu de

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

Puis-je faire quelque chose comme

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

Comme Textbox est une sous-classe de contrôle dans ce cas?

Mise à jour: J'ai également besoin de stocker ces deux délégués ControlInitialiser dans un e.b.

Dictionary<string, ControlInitializer> 

va spécifier

Dictionary<string, ControlInitializer<Control>> 

Les travaux dans ce cas que je ne peux pas sembler le faire fonctionner.

Merci d'avance.

+1

Vous pouvez utiliser l'action au lieu de définir votre propre délégué si vous utilisez .NET Framework 3.5. –

+1

'Action ' est également disponible dans .net 2.0 –

Répondre

10

Vous pouvez faire le délégué générique:

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

Et puis utiliser comme ceci:

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

Je suppose que votre but pour quelque chose comme ceci:

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); 
} 

C'est un peu difficile en raison de la r easons mentionnés dans David B La réponse. Ce que vous pouvez faire, cependant, est le type cache derrière une abstraction jeté, comme ceci:

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

Semble bon. Si j'ai un Dictionary qui stocke ceux-ci dans une variable statique, puis-je l'initialiser en utilisant Dictionary > et ajouter des délégués "un" et "deux"? –

+0

Non, à cause de la covariance de type –

3

Tout d'abord, utilisez le délégué prédéfini Action. En ce qui concerne la spécification du type, utilisez des arguments génériques:

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

Le délégué Action prend jusqu'à 4 arguments et ne retourne rien (void).

+0

Je réalise ceci mais cet exemple est une légère abstraction et Action ne s'appliquerait pas à la réalité. –

+0

alors il y a toujours 'Predicate' et' Func' de la version 3.5 –

2

Vous ne pouvez pas ajouter à un ControlInitializer<TextBox> à un dictionnaire qui tient ControlInitializer<Control>parce que le premier type ne hérite pas du second type (même si TextBox hérite de Control.) Il est tout au sujet du manque de Covariance et Contravariance dans les génériques.

Vous pourriez écrire votre propre collection pour se comporter de la manière que vous attendez.Voici une possibilité:

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; 
    } 
} 

Ce qui pourrait être utilisé de cette façon:

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

Sera-t-il possible de réaliser ceci dans .Net 4.0 qui introduit les variances co et contra? – Giorgi

Questions connexes