2009-08-27 4 views
18

Est-il possible de chasser les arguments param en C#? J'ai:Coulée des paramètres C# out?

Dictionary<string,object> dict; // but I know all values are strings 
string key, value; 

En gros (et si je n'ai pas typage statique) Je veux faire:

dict.TryGetValue(key, out value); 

mais ce sera évidemment pas compiler parce qu'il « ne peut pas convertir « en chaîne 'to' out objet '".

La solution que je utilise est:

object valueAsObject; 
dict.TryGetValue(key, out valueAsObject); 
value = (string) valueAsObject; 

mais qui semble plutôt maladroite.

Existe-t-il une sorte de fonctionnalité de langage pour me permettre de lancer un param de sortie dans l'appel de méthode, alors cela fait-il du switcheroo pour moi? Je ne peux pas trouver de syntaxe qui puisse aider, et je n'arrive pas à trouver quoi que ce soit avec google.

Répondre

2

Si vous savez que toutes les valeurs sont des chaînes, utilisez plutôt Dictionary<string, string>. Le type de paramètre out est défini par le type du deuxième paramètre de type générique. Puisque votre objet est actuellement objet, il retournera un objet lors de la récupération du dictionnaire. Si vous le changez en chaîne, il retournera des chaînes.

+4

Le Dictionary est fourni par une interface que j'utilise. Je sais que toutes les valeurs sont des chaînes pour mon utilisation, parce que c'est ce que je suis en train de remplir ici. – Ken

0

Non, vous ne pouvez pas. Le code à l'intérieur de la méthode modifie directement la variable qui lui est transmise, une copie du contenu de la variable n'est pas transmise.

2

Non, il n'y a pas moyen de contourner cela. Le paramètre out doit avoir une variable qui correspond exactement. L'utilisation d'une référence de chaîne n'est pas sûre, car le dictionnaire peut contenir d'autres éléments que des chaînes. Cependant, si vous avez un dictionnaire de chaînes et que vous essayez d'utiliser une variable d'objet dans l'appel TryGetValue, cela ne fonctionnera pas non plus, même si cela serait sûr. Le type de variable doit correspondre exactement.

18

Je ne sais pas si c'est une excellente idée, mais vous pouvez ajouter une méthode d'extension générique:

static bool TryGetTypedValue<TKey, TValue, TActual>(
     this IDictionary<TKey, TValue> data, 
     TKey key, 
     out TActual value) where TActual : TValue 
    { 
     TValue tmp; 
     if (data.TryGetValue(key, out tmp)) 
     { 
      value = (TActual)tmp; 
      return true; 
     } 
     value = default(TActual); 
     return false; 
    } 
    static void Main() 
    { 
     Dictionary<string,object> dict 
      = new Dictionary<string,object>(); 
     dict.Add("abc","def"); 
     string key = "abc", value; 
     dict.TryGetTypedValue(key, out value); 
    } 
+0

Ceci est un morceau intéressant de sucre syntaxique. –

+0

+1 n'a jamais fait cela sur un dictionnaire, mais a des méthodes d'aide très similaires. –

+1

La seule chose que je pourrais envisager de changer serait la gestion du cas où la valeur est trouvée mais est du mauvais type. Au lieu de jeter, je pourrais vouloir juste retourner faux. Ensuite, je ne pourrais pas. Je dois y réfléchir, mais cela vaut la peine d'être mentionné. –

2

J'utilise la méthode d'extension de Marc mais il a ajouté un peu à elle. Mon problème avec l'original était que dans certains cas, mon dictionnaire contiendrait un int64 alors que je m'attendrais à un int 32. Dans d'autres cas, le dictionnaire contiendrait une chaîne (par exemple "42") alors que je voudrais obtenir comme un int.

Il n'y a aucun moyen de gérer la conversion dans la méthode de Marc alors j'ai ajouté la possibilité de passer un délégué à une méthode de conversion:

internal static bool TryGetTypedValue<TKey, TValue, TActual>(
     this IDictionary<TKey, TValue> data, 
     TKey key, 
     out TActual value, Func<TValue, TActual> converter = null) where TActual : TValue 
    { 
     TValue tmp; 
     if (data.TryGetValue(key, out tmp)) 
     { 
      if (converter != null) 
      { 
       value = converter(tmp); 
       return true; 
      } 
      if (tmp is TActual) 
      { 
       value = (TActual) tmp; 
       return true; 
      } 
      value = default(TActual); 
      return false; 
     } 
     value = default(TActual); 
     return false; 
    } 

que vous pouvez appeler comme ceci:

int limit; 
myParameters.TryGetTypedValue("limitValue", out limit, Convert.ToInt32)