395 votes

L'opérateur == ne peut-il pas être appliqué aux types génériques en C #?

Selon la documentation de l' == opérateur dans MSDN,

Pour les prédéfinis des types de valeur, la opérateur d'égalité (==) retourne vrai si les valeurs de ses opérandes sont égaux, sinon false. Pour les types référence autres que string, == retourne true si ses deux opérandes reportez-vous à la même objet. Pour le type de chaîne, == compare les valeurs des chaînes de caractères. Valeur définie par l'utilisateur les types de surcharge l'opérateur = = (voir opérateur). Donc peut défini par l'utilisateur des types de référence, bien que par défaut == se comporte comme décrit ci-dessus pour les deux prédéfinis et défini par l'utilisateur des types référence.

Alors pourquoi ce bout de code ne parviennent pas à compiler?

void Compare<T>(T x, T y) { return x == y; }

Je reçois le message d'erreur de l'Opérateur '==' ne peut pas être appliquée à des opérandes de type " T " et "T". Je me demande pourquoi, depuis aussi loin que je comprends l' == opérateur est prédéfini pour tous les types?

Edit: Merci à tous. Je n'avais pas remarqué au premier abord que la déclaration a propos des types de référence seulement. Je pensais aussi que bit-par-bit de comparaison est fourni pour tous les types de valeur, qui je sais n'est pas correct.

Mais, dans le cas où je suis en utilisant un type de référence, serait l' == opérateur prédéfini référence de comparaison, ou d'utiliser la version surchargée de l'opérateur si un type défini?

Edit 2: Par essais et erreurs, nous avons appris que le == de l'opérateur utilisera le prédéfinies de référence de comparaison lors de l'utilisation sans restriction de type générique. En fait, le compilateur utilisera la meilleure méthode, il peut trouver de l'restreinte type d'argument, mais ne cherchez pas plus loin. Par exemple, le code ci-dessous est toujours imprimé true, même lorsqu' Test.test<B>(new B(), new B()) s'appelle:

class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test<T>(T a, T b) where T : A { Console.WriteLine(a == b); } }

348voto

Jon Skeet Points 692016

Comme d'autres l'ont dit, il ne fonctionne que lorsque T est contraint d'être un type de référence. Sans contraintes, vous pouvez comparer avec la valeur null, mais seulement nulle, et que la comparaison sera toujours faux pour non nullable types de valeur.

Au lieu de l'appel d'égal à Égal, il est préférable d'utiliser un IComparer<T> - et si vous n'avez pas plus d'informations, EqualityComparer<T>.Default est un bon choix:

public bool Compare<T>(T x, T y)
{
    return EqualityComparer<T>.Default.Equals(x, y);
}

À côté de quelque chose d'autre, cela évite de boxe et de casting.

161voto

Giovanni Galbo Points 8139

"...par défaut == se comporte comme décrit ci-dessus pour les deux prédéfinis et définis par l'utilisateur des types référence."

Type T n'est pas nécessairement un type de référence, de sorte que le compilateur ne peut pas faire une telle supposition.

Cependant, cela va compiler, car il est plus explicite:

    bool Compare<T>(T x, T y) where T : class
    {
        return x == y;
    }

Suivez supplémentaires jusqu'à la question, "Mais, dans le cas où je suis en utilisant un type de référence, serait l'opérateur == utiliser le prédéfinies de référence de comparaison, ou d'utiliser la version surchargée de l'opérateur si un type défini un?"

J'aurais pensé qu' == sur les Génériques serait d'utiliser la version surchargée, mais le test suivant démontre le contraire. Intéressant... j'aimerais savoir pourquoi! Si quelqu'un sait s'il vous plaît partager.

namespace TestProject
{
 class Program
 {
    static void Main(string[] args)
    {
        Test a = new Test();
        Test b = new Test();

        Console.WriteLine("Inline:");
        bool x = a == b;
        Console.WriteLine("Generic:");
        Compare<Test>(a, b);

    }


    static bool Compare<T>(T x, T y) where T : class
    {
        return x == y;
    }
 }

 class Test
 {
    public static bool operator ==(Test a, Test b)
    {
        Console.WriteLine("Overloaded == called");
        return a.Equals(b);
    }

    public static bool operator !=(Test a, Test b)
    {
        Console.WriteLine("Overloaded != called");
        return a.Equals(b);
    }
  }
}

Sortie

En ligne: Surchargé == appelé

Générique:

Appuyez sur n'importe quelle touche pour continuer . . .

Suivi De 2

Je ne veux point changer ma méthode de comparaison à

    static bool Compare<T>(T x, T y) where T : Test
    {
        return x == y;
    }

les causes de la surcharge opérateur == pour être appelé. Je suppose, sans en préciser le type ( ), le compilateur ne peut pas en déduire qu'il doit utiliser l'opérateur surchargé... mais je pense qu'il aurait suffisamment d'informations pour prendre une décision, même sans en préciser le type.

49voto

Marc Gravell Points 482669

En général, EqualityComparer<T>.Default.Equals devrait faire le travail avec tout ce qui implémente IEquatable<T>, ou qui a un bon Equals mise en œuvre.

Si, toutefois, == et Equals sont mis en œuvre différemment pour une raison quelconque, alors mon travail sur les opérateurs génériques devrait être utile; il prend en charge l' opérateur versions de (entre autres):

  • L'égalité(T valeur1, T valeur2)
  • NotEqual(T valeur1, T valeur2)
  • GreaterThan(T valeur1, T valeur2)
  • LessThan(T valeur1, T valeur2)
  • GreaterThanOrEqual(T valeur1, T valeur2)
  • LessThanOrEqual(T valeur1, T valeur2)

43voto

Ben Voigt Points 151460

Si de nombreuses réponses, et pas un seul n'explique le POURQUOI? (Giovanni explicitement demandé)...

.NET les génériques n'agissent pas comme des modèles C++. Dans les modèles C++, résolution de surcharge se produit après que le modèle actuel et les paramètres sont connus.

Dans .NET génériques (notamment en C#), résolution de surcharge se produit sans en connaître la réelle paramètres génériques. La seule information que le compilateur peut utiliser pour choisir la fonction à appeler provient du type de contraintes sur les paramètres génériques.

16voto

La compilation ne peut pas savoir T ne pouvait pas être un struct (valeur type). Donc, vous avez à le faire qu'il ne peut être de type référence, je pense que:

bool Compare<T>(T x, T y) where T : class { return x == y; }

C'est parce que si T pourrait être un type de la valeur, il pourrait y avoir des cas où x == y serait mal formé, dans les cas où un type n'a pas un opérateur == définies. La même chose se produira pour ce qui est de plus en plus évidents:

void CallFoo<T>(T x) { x.foo(); }

Qui ne trop, parce que vous pouvez passer d'un type T qui n'aurait pas une fonction foo. C# vous oblige à assurez-vous que tous les types possibles de toujours avoir une fonction foo. Cela est fait par la clause where.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X