2010-02-26 4 views
2

Après une recherche en ligne et en passant par les anciens postes de stackoverflow pour une mise en œuvre appropriée pour la commande dynamique avec linq, je suis venu avec ma propre mise en œuvre borrows a few things d'autres solutions que j'ai vu précédemment.Est-ce que cette méthode LINQ dynamic orderby est sûre?

Ce que je dois savoir est si cette implémentation est threadsafe? Je ne crois pas que je passe un objet de type générique énumérable (type de référence) en tant que paramètre dans la méthode statique mais je voudrais savoir si je manque quelque chose d'autre et j'espère comment le rendre complètement sécurisé.

public class OrderByHelper 
{ 

    public static IEnumerable<T> OrderBy<T>(IQueryable<T> items, string sortColumn, string sortDirection, int pageNumber, int pageSize) 
    { 
     Type t = typeof(T).GetProperty(sortColumn).PropertyType; 
     return (IEnumerable<T>)(typeof(OrderByHelper) 
         .GetMethod("OrderByKnownType") 
         .MakeGenericMethod(new[] { typeof(T), t }) 
         .Invoke(null, new object[] { items, sortColumn, sortDirection, pageNumber, pageSize })); 
    } 

    public static IEnumerable<K> OrderByKnownType<K, T>(IQueryable<K> items, string sortColumn, string sortDirection, int pageNumber, int pageSize) 
    { 
     var param = Expression.Parameter(typeof(K), "i"); 
     var mySortExpression = Expression.Lambda<Func<K, T>>(Expression.Property(param, sortColumn), param); 

     if (!string.IsNullOrEmpty(sortDirection)) 
     { 
      if (sortDirection == "ASC") 
       return items.OrderBy(mySortExpression).Skip((pageNumber - 1) * pageSize).Take(pageSize); 
      else 
       return items.OrderByDescending(mySortExpression).Skip((pageNumber - 1) * pageSize).Take(pageSize); 
     } 
     else 
      throw new InvalidOperationException("No sorting direction specified."); 
    } 
} 

Répondre

2

La réponse est simple:

Il est thread-safe si votre collection d'origine est thread-safe.

Toutes les méthodes d'extension dans LINQ appellent simplement .GetEnumerator() de la collection d'origine. Le tri et la commande ne manipulent pas la collection d'origine, mais vous permettent plutôt de l'énumérer dans un ordre trié. Ainsi, vous ne faites que lire les opérations sur les données. En règle générale, si vous ne lisez que des données, vous n'avez pas besoin d'implémenter une sécurité de thread. Je suis tenté de dire que dans 99% des cas, vous n'avez besoin d'aucune sécurité de thread, parce que vous ne collectez des données qu'une seule fois et ensuite exposez la fonctionnalité LINQ. Vous pourriez avoir besoin d'une collection thread-safe si vous voulez créer un framework qui n'instancie pas de nouvelles collections lors de l'actualisation des données, mais réutilise plutôt la même instance de collection (observable) qui se synchronise avec les données de la base de données.

Mais je ne connais pas votre scénario exact. Si nécessite vraiment la sécurité des threads, cela dépend si vous avez le contrôle sur le code où la collection d'origine est instanciée et les données sont ajoutées.

Si vous utilisez simplement LINQ-to-objects, vous avez entièrement le choix de créer une instance d'une classe de collection thread-safe à cet emplacement. Si vous utilisez LINQ-to-SQL ou quoi que ce soit, cela peut être difficile car la collection d'origine qui collecte les données de la base de données est probablement instanciée en profondeur dans le fournisseur et cachée à vous. Je ne l'ai pas regardé cependant s'il y a des points d'extension où vous pouvez substituer des choses pour employer une collection sûre de fil à la place.