2009-11-24 24 views
2

J'aime la programmation défensive. Je déteste les lancers d'exception, mais ce n'est pas le sujet de ma question.IOrdered Programmation défensive et en nombre

J'adapté une extension à LINQ pour être en mesure d'effectuer une commande par un nom de colonne

 public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, string sortExpression) 

Avec programmation défensive, cette méthode renvoie la dénombrable donnée si le nom de la colonne est pas valide.

Maintenant, je dois effectuer un tri secondaire avec ThenBy. donc j'ai besoin de cette signature:

 public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> list, string sortExpression) 

J'ai besoin de retourner un IOrderedEnumerable. Mon problème est de garder ma fonction de programmation défensive: Je dois retourner l'ensemble donné si le nom de la colonne n'est pas valide.

Existe-t-il une manière propre de faire ceci? Tout ce que je pense sont des sortes de trucs:

  • Utilisez la réflexion à l'ordre par la première propriété trouvée, ce qui est risqué parce que la propriété ne peut pas être tri-permis
  • Mettre en oeuvre mon propre IOrderedEnumerable, ce qui est risqué aussi parce que j'effectue la commande sur IQueryable ou IList, alors j'effectue d'autres opérations de LinQ, ainsi j'ai peur des effets secondaires.

Et des conseils/suggestions? Merci

+0

Comment est sortie de retour qui ne se rapporte pas à ce qui était demandé dans la façon dont il a été demandé plus défensif que de jeter une exception, attrapant à une couche particulière, l'afficher d'une manière appropriée au type de programme, et d'être plus confiant que les bugs n'ont pas été introduits par d'autres codes en supposant que la méthode pour commander les énumérables enumerables enumerables? Cela semble être le contraire de la programmation défensive. –

Répondre

3

Vous pouvez commander. Si la colonne n'existe pas, laissez votre entrée enumerable comme avant. Pour ce faire, créez un sélecteur de clé qui renvoie la même valeur pour tous les éléments.

Voir l'exemple:

using System; 
using System.Linq; 
using System.Collections.Generic; 
using System.Reflection; 

static class Program 
{ 
    public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> list, string sortExpression) where T : class 
    { 
     Func<T, Int32> keySelector = (elem) => 
     { 
      PropertyInfo pi = typeof(T).GetProperty(sortExpression, typeof(Int32)); 
      if (pi == null) 
       return 0; // return the same key for all elements 

      return Int32.Parse(pi.GetValue(elem, null).ToString()); 
     }; 

     return list.OrderBy(keySelector); 
    } 

    static void Main(string[] args) 
    { 
     // Create an array of strings to sort. 
     string[] fruits = { "apricot", "orange", "banana", "mango", "apple", "grape", "strawberry" }; 

     // Sort by "column" Length 
     foreach (string s in fruits.OrderBy<string>("Length")) 
      Console.WriteLine(s); 
     Console.WriteLine(); 

     // Sort by non-existing column 
     foreach (string s in fruits.OrderBy<string>("ength")) 
      Console.WriteLine(s); 
     Console.ReadKey(); 
    } 
} 
+0

Notez que "colonne" dans cet exemple a le type Int32 et est juste une des propriétés de l'élément. Vous pouvez avoir à la place une chaîne ou créer une méthode générique. –

+0

Notez que commander quand la clé est toujours la même (0 dans mon exemple) ** ne vous garantit pas que la sortie aura le même ordre que l'entrée. Je pense que ce sera la même chose, mais l'ordre formel peut être indéterminé dans ce cas. –

+0

L'ordre indéterminé n'est pas un problème si le nom de votre colonne est erroné, tant que le résultat est le même que l'entrée. Je ne veux tout simplement pas vérifier si le résultat est nul ou attraper une exception;) Merci pour votre réponse, content de votre aide. Je vais le tester dès que possible. – Mose