Por que Atributo condicional do .NET provocar efeitos secundários de ser removido?
-
03-07-2019 - |
Pergunta
Eu li sobre o atributo Conditional
hoje. De acordo com MSDN:
A aplicação
ConditionalAttribute
a um método indica a compiladores que uma chamada para o método não deve ser compilado em Microsoft Intermediate Language (MSIL) a menos que o símbolo de compilação condicional que está associado comConditionalAttribute
está definido.
OK. Isso é claro. Assim, a chamada para o método não será compilado. Mas o que sobre os efeitos colaterais?
[Conditional("UndefinedCondition")]
static void f1(int x) { Console.WriteLine(x); }
static int a = 0;
static void f2() { f1(++a); }
Assim, quando f2
é chamado, a chamada para f1
deve ser removido. Mas por que é ++a
removidas também? Este does't faz qualquer sentido para mim!
Solução
Expandindo resposta de Marc.
Este é definitivamente "By Design". A melhor maneira de entender a racionalização para isso é pensar sobre o que este código tomou o lugar de. Esta característica em muitos, e muito formas mais limpas, toma a forma de código condicionalmente compilado.
Por exemplo,
#if DEBUG
f1(++a);
#endif
Ou uma outra versão
#define f1(x) ...
No caso non-debug há claramente sem efeitos colaterais. Este é o mesmo comportamento para o código [condicional]. Concordo que é definitivamente não é tão claro como o primeiro exemplo, mas é tão claro como o segundo.
Outras dicas
Sim, todas as chamadas necessárias para argumentos são removidas também. Isto significa que para o caso de uso típico (compilações de depuração) você remove toda a expressão, que normalmente é o que se pretende.
Basicamente, você precisa ter muito cuidado ao usar métodos [Conditional]
, ou igualmente (em C # 3.0) métodos parciais - que têm um comportamento muito semelhante, se a outra metade do método parcial não é implementada. Como exemplo (para métodos parciais), ver abaixo. Note-se que a chamada para HasSideEffect()
é removido (descomente a outra metade do Bar
para vê-lo funcionar):
using System;
partial class Foo {
partial void Bar(string value);
static void Main() {
Foo foo = new Foo();
foo.Bar(HasSideEffect());
}
static string HasSideEffect() {
Console.WriteLine("hello");
return "world";
}
}
partial class Foo {
/* uncomment this
partial void Bar(string value) {
Console.WriteLine(value);
}*/
}
Eu acho que é devido à facilidade de implementação do compilador.
Eu ficaria com medo de tal código de qualquer maneira (mesmo que trabalhou como você espera que ele) e escrevê-lo como
++a;
f1(a);
para maior clareza. Você sempre pode ver o que é executado eo que não é.
Eu também suspeito que este comportamento é projetado para ser o mesmo que C pré-processador macros, que normalmente são configurados para não avaliar os argumentos quando não estiver em uso.