2009-09-16 7 views
0

Dans mon code, je crée un certain nombre de tables de recherche.Déclaration séparée et création de dictionnaire avec clé anonyme

var Dict1 = data1.ToDictionary(dim => new { dim.Val1,dim.Val2,.. } ); 
var Dict2 = data2.ToDictionary(dim => new { dim.Val1,dim.Val2,.. } ); 

parfois il y a des valeurs de clé, j'ai donc essayé d'utiliser un bloc catch

try 
{ 
    var Dict1 = data1.ToDictionary(dim => new { dim.Val1,dim.Val2,.. } ); 
} 
catch (ArgumentException ex) 
{ 
    Console.WriteLine("Duplicate values in Data1 {0}",ex); 
    throw; 
} 

mais cette approche signifie que les Dicts ne seront pas visibles pour le reste du code.

Des idées sur comment faire cela? Editer: l'intention du bloc catch est de signaler quelle création de dictionnaire a échoué.

+0

Le premier exemple est-il compilé? Je reçois "Un type anonyme ne peut pas avoir plusieurs propriétés avec le même nom" et beaucoup de "Déclarant de membre de type anonyme non valide.Les membres de type anonyme doivent être déclarés avec une affectation de membre, un nom simple ou un accès membre." – dtb

+0

Il compile avec le code réel, mais le code ci-dessus a été assaini –

Répondre

2

Déclarez et ajoutez un seul élément au-dessus de l'essai, puis ajoutez le reste à l'intérieur. Puisque vous êtes spécifiquement préoccupé par les clés en double, l'ajout de la première clé/élément vous permet d'obtenir le type sans risque.

EDIT: Je pense que inférer le type, sans ajouter le premier élément, est légèrement meilleur. Bien que l'utilisation soit un peu lourde, il vous sera plus facile d'ajouter des éléments restants (par opposition à l'effacement du dictionnaire, puis d'ajouter - ou d'ajouter tout ce qui suit le premier - uniquement si vous consommez un IEnumerable).

var dict1 = InferDictionary(new { Value1 = 0, Value2 = "string" }, new DataItem()); 
try { 
    data1.AddToDictionary(
    dict1, 
    dim => new { Value1 = dim.Val1, Value2 = dim.Val2 } 
); 
} catch ... { 
    ... 
} 

static IDictionary<TKey, TValue> InferDictionary<TKey, TValue>(TKey keyPrototype, TValue valuePrototype) { 
    return new Dictionary<TKey, TValue>(); 
} 

Ou, créer une fonction pratique pour intercepter l'exception pour vous:

var dict1 = TryCatch(
() => 
     data1.ToDictionary(dim => new { 
     Value1 = dim.Val1, 
     Value2 = dum.Val2 
     } 
    , (ArgumentException ex) => { 
     Console.WriteLine("Duplicate values in Data1 {0}", ex); 
    // throw(ex) works as well, and shouldn't screw the callstack up much 
    // But I happen to like making it explicit 
    return false; 
    } 
); 

static TResult TryCatch<TResult, TException>(Func<TResult> @try, Func<TException, bool> @catch) where TException : Exception { 
    try { 
     return @try(); 
    } catch (Exception ex) { 
     TException tEx = ex as TException; 
     if (tEx != null && @catch(ex)) { 
      // handled 
     } else { 
      throw; 
     } 
    } 
} 

La mise en garde est que vous ne pouvez pas appeler TryCatch<,> dans les voies « naturelles »:

// Not enough info to infer TException 
var d = TryCatch(() => DoStuff(), ex => true); 

// Can't infer only TResult 
var d = TryCatch<ArgumentException>(() => DoStuff(), ex => true); 
Ce qui, puisque vous ne pouvez pas spécifier TResult, vous oblige dans la syntaxe quelque peu étrange de déclarer TException sur le lambda:
var d = TryCatch(() => DoStuff(), (ArgumentException ex) => true); 
+0

Je ne peux pas déclarer l'élément, car c'est un type anoymous, mais j'aime l'idée de code! –

+0

Vous pouvez utiliser une fonction d'assistance pour obtenir le dictionnaire créé.AAMOF, vous pourriez simplement créer un dictionnaire vide, ce qui serait probablement plus raisonnable - à la taxe laide de simplement utiliser un paramètre comme un «prototype». Vous auriez cependant besoin d'échanger votre méthode data.ToDictionary avec AddToDictionary. –

0

Vous pouvez déclarer la variable Dict1 en dehors du bloc try catch.

0

Y a-t-il une raison d'utiliser le bloc try/catch? Vous n'ajoutez aucune valeur à votre programme en plus d'écrire sur la console. Si vous étiez en train de traiter les erreurs, je pouvais voir comment résoudre ce problème, mais je laisserais l'exception se produire et je ne tenterais pas de l'attraper du tout.

+0

Ce n'est pas pour la gestion des erreurs, mais les diagnostics –

0

Vous allez faire beaucoup d'efforts pour éviter de déclarer un nouveau type. Les types anonymes sont pratiques lorsque vous avez une construction de données très spécifique que vous prévoyez de ne plus jamais utiliser dans un autre endroit de votre code. Dans ce cas, vous voulez représenter le même type à plusieurs endroits, donc la meilleure solution est probablement de créer simplement une classe pour représenter ce type. Vous pouvez en faire une classe imbriquée privée pour éviter de polluer votre espace de type en dehors de cette classe.

Questions connexes