Para que serve o operador falso em C #?

107

Existem dois operadores estranhos em C #:

Se entendi bem, esses operadores podem ser usados ​​em tipos que desejo usar em vez de uma expressão booleana e onde não desejo fornecer uma conversão implícita para bool.

Digamos que eu tenha uma aula a seguir:

    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;
        }

    }

Portanto, posso escrever o seguinte código:

    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)

No entanto, para todos os exemplos acima, apenas o operador verdadeiro é executado. Então, para que serve o operador falso em C #?

Nota: Mais exemplos podem ser encontrados aqui , aqui e aqui .

Jakub Šturc
fonte
Documentos modernos podem ser encontrados em docs.microsoft.com/en-us/dotnet/csharp/language-reference/… . Os documentos sugerem que não há mais razão para definir esse operador, já que o C # 2.0 adicionou tipos anuláveis.
Mark Amery

Respostas:

65

Você pode usá-lo para substituir os operadores &&e ||.

Os &&e ||operadores não pode ser substituído, mas se você substituir |, &, truee falseexatamente da maneira certa o compilador irá chamar |e &quando você escreve ||e &&.

Por exemplo, veja este código (de http://ayende.com/blog/1574/nhibernate-criteria-api-operator-overloading - onde descobri este truque; versão arquivada por @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;
}

Obviamente, esse é um efeito colateral e não a forma como deve ser usado, mas é útil.

Nir
fonte
seu link é 404. Não tenho certeza de como deseja editar isso, então deixei como está.
user7116
Eu atualizei a URL com uma cópia arquivada para que ainda possa ser lida.
IAmTimCorey
25

Shog9 e Nir: obrigado por suas respostas. Essas respostas apontou-me a artigo Steve Eichert e ele me apontou para MSDN :

A operação x && y é avaliada como T.false (x)? x: T. & (x, y), onde T.false (x) é uma invocação do operador falso declarado em T, e T. & (x, y) é uma invocação do operador selecionado &. Em outras palavras, x é avaliado primeiro e o operador falso é invocado no resultado para determinar se x é definitivamente falso. Então, se x for definitivamente falso, o resultado da operação será o valor calculado anteriormente para x. Caso contrário, y é avaliado e o operador selecionado & é invocado no valor calculado anteriormente para xe o valor calculado para y para produzir o resultado da operação.

Jakub Šturc
fonte
Eu me pergunto por que eles não optaram por usar a (!T.true(x)) ? x : T.&(x, y)lógica em vez disso.
Des Nerger
14

A página que você vincula a http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspx diz para que eles serviam, que era uma maneira de lidar com bools anuláveis ​​antes que os tipos de valor anuláveis ​​fossem introduzidos.

Eu acho que hoje em dia eles são bons para o mesmo tipo de coisa que ArrayList - ou seja, absolutamente nada.

Will Dean
fonte
7

AFAIK, seria usado em um teste de falso, como quando o &&operador entra em jogo. Lembre-se, && curto-circuitos, então na expressão

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

mFalse.false()é chamado e, ao retornar, truea expressão é reduzida a uma chamada para 'mFalse.true ()' (que deve retornar false, ou as coisas ficarão estranhas).

Observe que você deve implementar o &operador para que a expressão seja compilada, já que ele é usado se mFalse.false()retornar false.

Shog9
fonte
3

Parece que o artigo do MSDN que você vinculou a ele foi fornecido para permitir tipos booleanos anuláveis ​​antes do tipo Anulável (ou seja, int ?, bool? Etc.) sendo introduzido na linguagem C # 2. Assim, você armazenaria um valor interno indicando se o valor é verdadeiro ou falso ou nulo, ou seja, em seu exemplo> 0 para verdadeiro, <0 para falso e == 0 para nulo, e então obteria semântica nula no estilo SQL. Você também teria que implementar um método ou propriedade .IsNull para que a nulidade pudesse ser verificada explicitamente.

Comparando com SQL, imagine uma tabela Table com 3 linhas com valor Foo definido como true, 3 linhas com valor Foo definido como false e 3 linhas com valor Foo definido como null.

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

Para contar todas as linhas, você terá que fazer o seguinte: -

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

Esta sintaxe 'IS NULL' teria código equivalente em sua classe como .IsNull ().

LINQ torna a comparação com C # ainda mais clara: -

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

Imaginando que MyTypeEnumberable tem exatamente o mesmo conteúdo do banco de dados, ou seja, 3 valores iguais a true, 3 valores iguais a false e 3 valores iguais a null. Nesse caso, totalCount seria avaliado como 6. No entanto, se reescrevermos o código como: -

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

Então, totalCount seria avaliado como 9.

O exemplo DBNull fornecido no artigo vinculado do MSDN sobre o operador falso demonstra uma classe na BCL que tem esse comportamento exato.

Na verdade, a conclusão é que você não deve usar isso a menos que esteja completamente certo de que deseja esse tipo de comportamento, é melhor apenas usar a sintaxe anulável, muito mais simples !!

Atualização: acabei de notar que você precisa substituir manualmente os operadores lógicos!, || e && para fazer isso funcionar corretamente. Eu acredito que o operador falso alimenta esses operadores lógicos, isto é, indicando verdade, falsidade ou 'outro'. Conforme observado em outro comentário! X não funcionará logo de cara; você tem que sobrecarregar! Estranheza!

ljs
fonte