2009-09-03 7 views
2

J'essaie d'appeler une méthode « Tri » qui attend un paramètre de type IComparer<object>, en utilisant le code:ne peut pas passer comparateur par défaut comme IComparer <object>

collection.Sort((IComparer<object>)Comparer<DateTime>.Default) 

Il construit, mais au moment de l'exécution je reçois une InvalidCastException avec le message:

Unable to cast object of type 
'System.Collections.Generic.GenericComparer`1[System.DateTime]' 
to type 'System.Collections.Generic.IComparer`1[System.Object]'. 

Maintenant, quoi?

+0

Veuillez poster la déclaration de "collection". Nous avons besoin de plus d'informations pour aider. –

+0

C'est une collection LLBL, à savoir SD.LLBLGen.Pro.upportClasses.EntityCollectionBase2 (maintenant vous êtes désolé, vous avez demandé :) – JoelFan

+0

Vous aurez besoin d'un comparateur personnalisé - si les types sont toujours des valeurs DateTIme, ce que je viens d'ajouter devrait fonctionner (avec seulement 5 lignes de code supplémentaires) –

Répondre

7

Si vous voulez simplement la comparaison par défaut, cela fonctionne:

collection.Sort(Comparer<object>.Default) 

Comparer.Default utilise vos objets sémantique de comparaison inhérente (c.-à-d., IComparable.CompareTo).

+0

Est-ce que cela compare 2 DateTime correctement? – JoelFan

+0

Oui, il le fera. J'ai édité ma réponse pour clarifier ceci. –

+0

Wow je l'ai essayé et ça marche! Je ne comprends pas pourquoi! – JoelFan

4

Malheureusement, vous devez avoir un comparateur du type approprié.

Vous pouvez créer une classe IComparer<object> personnalisée qui vient d'être enveloppée par le comparateur de date et heure, mais il n'existe aucun moyen de le faire directement via une distribution.

Si votre collection contient toujours des objets DateTime, vous pouvez juste faire:

ICollection<DateTime> collection = ...; 
collection.Sort(Comparer<DateTime>.Default); // or just collection.Sort() 

Modifier après avoir lu le commentaire:

Si vous travaillez avec un ICollection directement, vous pouvez voulez utiliser l'option LINQ à faire:

collection.Cast<DateTime>().OrderBy(date => date); 

Si vous travaillez avec quelque chose qui implémente IList<T>, (tel que List<DateTime>) vous pouvez simplement appeler Sort() sur la liste elle-même.


Puisque vous utilisez une classe non standard, vous devrez faire votre propre comparateur:

class Comparer : IComparer<object> { 
    int Compare(object a, object b) { 
     return DateTime.Compare((DateTime)a, (DateTime)b); 
    } 
} 

Vous pouvez ensuite appeler:

collection.Sort(new Comparer()); 
+0

J'ai obtenu: 'System.Collections.Generic.ICollection ' ne contient pas de définition pour 'Trier' et pas de méthode d'extension 'Trier' acceptant un premier argument de type 'System.Collections.Generic.ICollection ' peut être trouvé (manque-t-il une directive using ou une référence d'assembly?) – JoelFan

+0

@JoelFan: J'ai édité ma réponse en réponse –

+0

L'option LINQ ne fonctionnera pas car je veux un tri "en mémoire" (LINQ OrderBy retourne une nouvelle collection). Et comme pour la deuxième suggestion, non, il ne met pas en œuvre IList :( – JoelFan

1

Juste essayer de supprimez la distribution et laissez le compilateur choisir IComparer au lieu de IComparer<T>.

Comparer<T> implémente à la fois IComparer<T> et IComparer alors cela devrait fonctionner.

Cela fonctionne très bien:

ArrayList collection = new ArrayList {DateTime.Now.AddDays(1), DateTime.Now}; 
collection.Sort(Comparer<DateTime>.Default); 
+0

Je reçois: ne peut pas convertir de 'System.Collections.Generic.Comparer ' en 'System.Collections.Generic.IComparer JoelFan

+0

juste pour être clair ... Je n'utilise pas ArrayList comme vous sont – JoelFan

+0

Essayez-vous d'utiliser une fonction de tri qui a ce genre (IComparer comparateur>) signature ou Trier (comparateur IComparer)? Quel est le type de votre collection? –

3

Si vous pouvez modifier le type de l'objet de collection (par exemple à un ArrayList d'un List<object>), alors vous pouvez simplement utiliser l'interface IComparer non générique (qui Comparer<DateTime>.Default met en oeuvre).

Si vous ne pouvez pas modifier le type de l'objet de collection, vous n'avez pas de chance. (Vous pouvez toujours mettre en œuvre un objet qui implémente IComparer<object>, comme ceci:

public class DateTimeComparer : IComparer<object> 
    {  
     public int Compare(object x, object y) 
     { 
      IComparer myComparer = Comparer<DateTime>.Default as IComparer; 
      return myComparer.Compare(x, y); 
     }  
    } 

(Cela lancera une exception si vous avez des éléments non DateTime dans votre collection si)

EDIT:

Vous pouvez également mettre en œuvre quelque chose d'un peu plus de type sécurité, à savoir:

public class DateTimeComparer : IComparer<object> 
    {  
     public int Compare(object x, object y) 
     { 
      if (x is DateTime && y is DateTime) 
      { 
       return Comparer<DateTime>.Default.Compare((DateTime) x, (DateTime) y); 
      } 
      else 
      { 
       // handle the type mismatch 
      } 
     }  
    } 
3

Vous pouvez définir une fonction d'extension comme ceci:

public static class ComparerConversion 
    { 
     private class ComparerWrapper<T> : IComparer<object> 
     { 
      private readonly IComparer<T> comparer; 

      public ComparerWrapper(IComparer<T> comparer) 
      { 
       this.comparer = comparer; 
      } 

      public int Compare(object x, object y) 
      { 
       return this.comparer.Compare((T)x, (T)y); 
      } 
     } 

     public static IComparer<object> ToObjectComparer<T>(this IComparer<T> comparer) 
     { 
      return new ComparerWrapper<T>(comparer); 
     } 
    } 

et l'utiliser comme ceci:

List<object> collection = new List<object> { DateTime.Now.AddDays(1), DateTime.Now }; 
collection.Sort(Comparer<DateTime>.Default.ToObjectComparer()); 
Questions connexes