À quoi sert le faux opérateur en C #?

107

Il y a deux opérateurs étranges en C #:

Si je comprends ce droit, ces opérateurs peuvent être utilisés dans des types que je souhaite utiliser à la place d'une expression booléenne et où je ne souhaite pas fournir une conversion implicite en booléen.

Disons que j'ai une classe suivante:

    public class MyType
    {
        public readonly int Value;

        public MyType(int value)
        {
            Value = value;
        }

        public static bool operator true (MyType mt)
        {
            return  mt.Value > 0;
        }

        public static bool operator false (MyType mt)
        {
            return  mt.Value < 0;
        }

    }

Je peux donc écrire le code suivant:

    MyType mTrue = new MyType(100);
    MyType mFalse = new MyType(-100);
    MyType mDontKnow = new MyType(0);

    if (mTrue)
    {
         // Do something.
    }

    while (mFalse)
    {
        // Do something else.
    }

    do
    {
        // Another code comes here.
    } while (mDontKnow)

Cependant, pour tous les exemples ci-dessus, seul l'opérateur vrai est exécuté. Alors, à quoi sert le faux opérateur en C #?

Remarque: D'autres exemples peuvent être trouvés ici , ici et ici .

Jakub Šturc
la source
Des documents modernes sont disponibles sur docs.microsoft.com/en-us/dotnet/csharp/language-reference/… . La documentation suggère qu'il n'y a plus de raison de définir cet opérateur puisque C # 2.0 a ajouté des types Nullable.
Mark Amery

Réponses:

65

Vous pouvez l' utiliser pour remplacer le &&et|| opérateurs .

Les &&et les ||opérateurs ne peuvent pas être surchargée, mais si vous substituez |, &, trueet falseexactement de la bonne façon le compilateur appeler |et &lorsque vous écrivez ||et&& .

Par exemple, regardez ce code (de http://ayende.com/blog/1574/nhibernate-criteria-api-operator-overloading - où j'ai découvert cette astuce; version archivée par @BiggsTRC):

public static AbstractCriterion operator &(AbstractCriterion lhs, AbstractCriterion rhs)
{
       return new AndExpression(lhs, rhs);
}

public static AbstractCriterion operator |(AbstractCriterion lhs, AbstractCriterion rhs)
{
       return new OrExpression(lhs, rhs);
}

public static bool operator false(AbstractCriterion criteria)
{
       return false;
}
public static bool operator true(AbstractCriterion criteria)
{
       return false;
}

C'est évidemment un effet secondaire et non la façon dont il est censé être utilisé, mais c'est utile.

Nir
la source
votre lien est 404. Je ne sais pas comment vous voulez éditer ceci, donc je l'ai laissé.
user7116
J'ai mis à jour l'URL avec une copie archivée afin qu'elle puisse toujours être lue.
IAmTimCorey
25

Shog9 et Nir: merci pour vos réponses. Ces réponses m'ont renvoyé à l'article de Steve Eichert et m'ont dirigé vers msdn :

L'opération x && y est évaluée comme T.false (x)? x: T. & (x, y), où T.false (x) est une invocation de l'opérateur false déclaré dans T, et T. & (x, y) est une invocation de l'opérateur sélectionné &. En d'autres termes, x est d'abord évalué et l'opérateur false est appelé sur le résultat pour déterminer si x est définitivement faux. Ensuite, si x est définitivement faux, le résultat de l'opération est la valeur précédemment calculée pour x. Sinon, y est évalué, et l'opérateur sélectionné & est appelé sur la valeur précédemment calculée pour x et la valeur calculée pour y pour produire le résultat de l'opération.

Jakub Šturc
la source
Je me demande pourquoi ils n'ont pas choisi d'utiliser la (!T.true(x)) ? x : T.&(x, y)logique à la place.
Des Nerger
14

La page vers laquelle vous créez un lien http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspx indique à quoi ils servaient, ce qui était un moyen de gérer les bools nullables avant l'introduction des types de valeurs nullables.

Je suppose que de nos jours, ils sont bons pour le même genre de choses que ArrayList - c'est-à-dire absolument rien.

Will Dean
la source
7

AFAIK, il serait utilisé dans un test de faux, par exemple lorsque l' &&opérateur entre en jeu. Rappelez-vous, && court-circuits, donc dans l'expression

if ( mFalse && mTrue) 
{
   // ... something
}

mFalse.false()est appelée, et lors du retour, truel'expression est réduite à un appel à 'mFalse.true ()' (qui devrait alors retournerfalse , choses deviendront bizarres).

Notez que vous devez implémenter l' &opérateur pour que cette expression se compile, car elle est utilisée si mFalse.false()renvoie false.

Shog9
la source
3

Il semble que l'article MSDN que vous y avez lié a été fourni pour autoriser les types booléens Nullable avant l'introduction du type Nullable (c'est-à-dire int ?, bool ?, etc.) dans le langage en C # 2. Ainsi, vous stockeriez une valeur interne indiquant si la valeur est vraie ou fausse ou nulle, c'est-à-dire dans votre exemple> 0 pour vrai, <0 pour faux et == 0 pour null, puis vous obtiendrez une sémantique nulle de style SQL. Vous devrez également implémenter une méthode ou une propriété .IsNull pour que la nullité puisse être vérifiée explicitement.

En comparant à SQL, imaginez une table Table avec 3 lignes avec la valeur Foo définie sur true, 3 lignes avec la valeur Foo définie sur false et 3 lignes avec la valeur Foo définie sur null.

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE
6

Afin de compter toutes les lignes, vous devez faire ce qui suit: -

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE OR Foo IS NULL
9

Cette syntaxe 'IS NULL' aurait un code équivalent dans votre classe comme .IsNull ().

LINQ rend la comparaison avec C # encore plus claire: -

int totalCount = (from s in MyTypeEnumerable
                 where s || !s
                 select s).Count();

Imaginons que MyTypeEnumberable a exactement le même contenu de la base de données, c'est à dire 3 valeurs égales à true, 3 valeurs égales à false et 3 valeurs égales à null. Dans ce cas, totalCount serait évalué à 6 dans ce cas. Cependant, si nous réécrivons le code comme suit: -

int totalCount = (from s in MyTypeEnumerable
                 where s || !s || s.IsNull()
                 select s).Count();

Alors totalCount serait évalué à 9.

L'exemple DBNull donné dans l'article MSDN lié sur l'opérateur false illustre une classe dans le BCL qui a ce comportement exact.

En effet, la conclusion est que vous ne devriez pas utiliser cela à moins que vous ne soyez complètement sûr de vouloir ce type de comportement, il est préférable d'utiliser simplement la syntaxe nullable beaucoup plus simple !!

Mise à jour: je viens de remarquer que vous devez remplacer manuellement les opérateurs logiques!, || et && pour que cela fonctionne correctement. Je crois que le faux opérateur alimente ces opérateurs logiques, c'est-à-dire indiquant la vérité, la fausseté ou «autrement». Comme indiqué dans un autre commentaire! X ne fonctionnera pas dès le départ; vous devez surcharger!. Étrangeté!

ljs
la source