Para que serve o operador falso em C#?
Pergunta
Existem dois operadores estranhos em C#:
Se bem entendi, esses operadores podem ser usados em tipos que desejo usar em vez de uma expressão booleana e onde não quero fornecer uma conversão implícita para bool.
Digamos que eu tenha a seguinte classe:
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;
}
}
Então 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#?
Observação:Mais exemplos podem ser encontrados aqui, aqui e aqui.
Solução
Você pode usá-lo para substituir o &&
e ||
operadores.
O &&
e ||
operadores não podem ser substituídos, mas se você substituir |
, &
, true
e false
exatamente da maneira certa que o compilador 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 esse 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, este é um efeito colateral e não a forma como deve ser usado, mas é útil.
Outras dicas
Shog9 e Nir:obrigado por suas respostas.Essas respostas me apontaram para Artigo de Steve Eichert e isso me indicou msdn:
A operação x && y é avaliada como T.false(x) ?x:T.&(x, y), onde T.false(x) é uma invocação do operador false declarado em T, e T.&(x, y) é uma invocação do operador & selecionado.Em outras palavras, x é primeiro avaliado e o operador false é invocado no resultado para determinar se x é definitivamente falso.Então, se x for definitivamente falso, o resultado da operação será o valor previamente calculado para x.Caso contrário, y é avaliado e o operador & selecionado é invocado no valor calculado anteriormente para x e no valor calculado para y para produzir o resultado da operação.
A página para a qual você vincula http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspx diz para que serviam, que era uma maneira de lidar com bools anuláveis antes da introdução dos tipos de valor anuláveis.
Eu acho que hoje em dia eles são bons para o mesmo tipo de coisa que ArrayList - ou seja,absolutamente nada.
AFAIK, seria usado em um teste para falso, como quando o &&
operador entra em jogo.Lembre-se, && curto-circuito, então na expressão
if ( mFalse && mTrue)
{
// ... something
}
mFalse.false()
é chamado, e ao retornar true
a expressão é reduzida a uma chamada para 'mFalse.true()' (que deve então retornar false
, ou as coisas ficarão estranhas).
Observe que você deve implementar o &
operador para que essa expressão seja compilada, já que é usado se mFalse.false()
retorna false
.
Parece que o artigo do MSDN ao qual você vinculou foi fornecido para permitir tipos booleanos anuláveis antes do Anulável (ou seja,int?, bool?, etc.) sendo introduzido na linguagem em C#2.Assim, você armazenaria um valor interno indicando se o valor é verdadeiro, falso ou nulo, ou seja,no seu exemplo >0 para verdadeiro, <0 para falso e ==0 para nulo, e então você 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 verdadeiro, 3 linhas com valor Foo definido como falso e 3 linhas com valor Foo definido como nulo.
SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE
6
Para contar todas as linhas, você teria 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 tenha exatamente o mesmo conteúdo do banco de dados, ou seja,3 valores iguais a verdadeiro, 3 valores iguais a falso e 3 valores iguais a nulo.Neste 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 dado no artigo vinculado do MSDN sobre o operador false 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 tenha certeza absoluta de que deseja esse tipo de comportamento; é melhor usar apenas a sintaxe anulável, muito mais simples!!
Atualizar: Acabei de notar que você precisa substituir manualmente os operadores lógicos!, || e && para fazer isso funcionar corretamente.Acredito que o operador falso alimenta esses operadores lógicos, ou seja,indicando verdade, falsidade ou 'não'.Conforme observado em outro comentário, !x não funcionará imediatamente;você tem que sobrecarregar!Estranheza!