2009-05-13 6 views
0

je farfouillé dans le réflecteur .NET, et a remarqué que pour les types de référence comme par exemple « String », il y a une surcharge explicite de l'opérateur « == »:.NET: Où est l'implémentation par défaut pour "==" op_Equality() pour les types de valeur?

typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public) 

retours: System.Reflection. MethodInfo pour l'opérateur "==".

En raison de sa mise en œuvre, vous ne pouvez pas faire des choses comme:

if("hi" == 3) // compiler error, plus code would throw an exception even if it ran) 

Cependant, la même chose fonctionne pour les types de valeur:

if((int)1 == (float)1.0) // correctly returns true 
if((int)1 == (float)1.2) // correctly returns false 

Je suis en train de comprendre exactement comment .NET gère en interne le processus de conversion de type, donc je cherchais l'implémentation de op_Equality() dans .NET Reflector, mais "int" n'en a pas.

typeof(int).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public) 

renvoie la valeur null. Alors, où est l'implémentation par défaut de l'opérateur "==" pour les types de valeur? Je voudrais pouvoir appeler via la réflexion:

public bool AreEqual(object x, object y) 
{ 
    if(x.GetType().IsValueType && y.GetType().IsValueType) 
     return x == y; // Incorrect, this calls the "object" equality override 
    else 
     ... 
} 

Edit # 1:

J'ai essayé, mais ça n'a pas marché:

(int)1 == (float)1;       // returns true 
System.ValueType.Equals((int)1, (float)1); // returns false 

Édition 2:

Également t ried, mais pas d'amour:

object x = (int)1; 
object y = (float)1.0; 

bool b1 = (x == y);     // b1 = false 
bool b2 = ((ValueType)x).Equals(y); // b2 = false 

Je beleive cet opérateur Equals sur ValueType ne fonctionne pas en raison de cette vérification de type (arraché à réflecteur .NET):

ValueType.Equals(object obj) 
{ 
    ... 

    RuntimeType type = (RuntimeType) base.GetType(); 
    RuntimeType type2 = (RuntimeType) obj.GetType(); 
    if (type2 != type) 
    { 
     return false; 
    } 

    ... 

Répondre

2

L'évaluation de (int) 1 == (float) 1.0 ne repose sur aucun opérateur spécial ==, juste les règles de conversion.

Le compilateur transformer cela en (float) ((int) 1) == (float) 1.0

Edit: Les règles sont spécifiées on MSDN.

+0

C'est sur la bonne voie. Y a-t-il un moyen de dire quelle devrait être la distribution appropriée? Par exemple, comment sait-il que le résultat est float au lieu de int? il doit y avoir un ordre de préséance quelque part ... – CodingWithSpike

+0

C'est correct. Si vous codez C# (int) 1 == (float) 1.0; Le compilateur va générer l'équivalent en IL de (float) 1.0 == (float) 1.0; Il met à jour l'int à la compilation, donc à l'exécution, les types sont égaux. – CodingWithSpike

1

Je devine que vous Recherchez ValueType.Equals(object obj) qui est héritée de vos structures. Il utilise la réflexion pour comparer tous les domaines.

+0

C'est le cas typique. Beaucoup plus communément, il fera une comparaison peu à peu – JaredPar

+0

Voir mon édition n ° 2 ci-dessus dans mon message original. – CodingWithSpike

2

Qu'est-ce que vous cherchez est ValueType.Equals

Dans de nombreux cas, cela ne juste un peu par comparaison binaire des valeurs. Dans certains cas, il utilisera la réflexion pour vérifier les champs.

EDIT

Vous confondez comment C# compare les types de valeurs et comment.Net compare les types de valeur. ValueType.Equals est une fonction dans .Net utilisée pour comparer des objets de type valeur qui ont le même type. C# va émettre du code qui appelle finalement cette fonction. Mais il ne l'appelle pas avec un "int" et un "float". Au lieu de cela, il les convertit d'abord en un type qui ne perd pas de précision pour l'une ou l'autre valeur (double), puis compare les valeurs doubles résultantes. C'est pourquoi vous voyez une différence de comportement.

+0

J'ai essayé, mais cela n'a pas fonctionné comme prévu. ValueType.Equals ((int) 1, (float) 1); renvoie false, l'opposé de: (int) 1 == (float) 1; – CodingWithSpike

+0

@ rally25rs, le code que vous avez écrit ne doit pas compiler AFAICT. ValueType.Equals est une méthode d'instance et ne prend qu'un seul paramètre. – JaredPar

+0

Je viens de remarquer qu'il y a un ValueType.Equals (objet, objet) hérité de Object, et un ValueType.Equals (object) qui est sur ValueType. J'appelais le mauvais. Oops! :) – CodingWithSpike

1

My answer à une autre question fournit l'implémentation du rotor. Le code réel est implémenté dans le CLR en tant que code natif.

Plus précisément:

// Compare the contents (size - vtable - sink block index). 
BOOL ret = memcmp(
    (void *) (pThisRef+1), 
    (void *) (pCompareRef+1), 
    pThisRef->GetMethodTable()->GetBaseSize() - sizeof(Object) - sizeof(int)) == 0; 
2

Où est l'implémentation par défaut pour ==op_Equality pour les types de valeur?

Il n'y a pas == par défaut pour les types de valeur. Essayez d'écrire votre propre type de valeur

struct JustAnotherValueType 
{ 
    public readonly int Field; 
    public JustAnotherValueType(int f) { Field = f; } 
} 

Faire deux valeurs x et y de votre type. Essayez de dire x == y avec eux. Il ne compilera pas. Vous pouvez dire

(object)x == (object)y 

mais qui effectuera la boxe sur x (Appelons-encadré 1) et la boxe sur y (encadré 2), puis effectuer une comparaison de référence sur les deux boîtes. Par conséquent, il reviendra toujours faux. Et par conséquent, il est inutile, et c'est la raison pour laquelle la surcharge ==(object x, object y) n'est pas automatiquement sélectionnée lorsque vous utilisez == entre deux JustAnotherValueType.

Alors, que se passe-t-il avec int et float? Vous pouvez les comparer avec == en C#, et ils n'ont pas la méthode op_Equality ?! L'explication est que ces surcharges sont définies par the C# Language Specification. Voir les sections Opérateurs de comparaison d'entiers et Opérateurs de comparaison à virgule flottante. Le fait est que, bien que ces opérateurs n'existent pas en tant que membres des structures .NET, la spécification de langage C# les définit, et le compilateur C# doit produire une IL valide pour imiter leur comportement. Par ailleurs, System.Object n'a pas de op_Equality non plus. C'est aussi seulement défini par C#. Voir la section Opérateurs d'égalité de type de référence. Notez que System.Object a une méthode ReferenceEquals que le compilateur peut choisir de traduire cette surcharge de == en. Notez également que cette section de la spécification donne des limitations de sorte que x == y n'effectuera jamais de boxe sur x ou y.

Qu'en est-il des types de valeur comme DateTime, TimeSpan et Guid qui ne sont pas mentionnés dans le C# Spécification, mais pour lequel il est légal d'utiliser ==? La réponse est, ces ont le membre op_Equality.

Conclusion: Le langage C# Spécification définit un grand nombre de == qu'une mise en œuvre des surcharges de C# est nécessaire d'avoir, et certaines de ces int et impliquent les surcharges float et object. Remarque: La méthode d'instance virtuelle Equals(object) est définie dans object et héritée par tous les types de valeurs. Pour les structures qui ne remplacent pas elles-mêmes cette méthode, le override dans System.ValueType est utilisé. Il compare par valeur. Donc, avec x et y comme ci-dessus, x.Equals(y) fonctionnera bien. Equals est une méthode d'instance virtuelle. D'autre part, == est une "méthode" static pour laquelle une résolution de surcharge basée sur les types de compilation des deux opérandes est effectuée (pas de "répartition virtuelle").

Questions connexes