Considérer les classes suivantes:
public class A {
public B GetB() {
Console.WriteLine("GetB");
return new B();
}
}
public class B {
[System.Diagnostics.Conditional("DEBUG")]
public void Hello() {
Console.WriteLine("Hello");
}
}
Maintenant, si nous devions appeler les méthodes de cette façon:
var a = new A();
var b = a.GetB();
b.Hello();
Dans un communiqué de construire (à savoir, pas de DEBUG
drapeau), nous ne voyons GetB
imprimé sur la console, comme l'appel à l' Hello()
serait omise par le compilateur. Dans une version debug, les deux copies apparaissent.
Maintenant, nous allons enchaîner les appels de méthode:
a.GetB().Hello();
Le comportement dans une version de débogage est inchangé; cependant, nous obtenons un résultat différent si l'indicateur n'est pas défini: les deux appels sont omis et aucun tirage apparaissent sur la console. Un rapide coup d'oeil à IL montre que l'ensemble de la ligne n'est pas compilé.
Selon la dernière norme ECMA pour C# (ECMA-334, c'est à dire de C# 5.0), le comportement attendu lors de l' Conditional
attribut est placé sur la méthode est la suivante (l'emphase est mienne):
Un appel à une condition méthode est inclus si un ou plusieurs de ses associés symboles de compilation conditionnelle est défini au moment de l'appel, sinon l'appel est omis. (§22.5.3)
Cela ne semble pas indiquer que l'ensemble de la chaîne doit être ignoré, d'où ma question. Cela étant dit, le C# 6.0 projet de spec à partir de Microsoft offre un peu plus en détail:
Si le symbole est défini, l'appel est inclus; sinon, l'appel (y compris l'évaluation du récepteur et les paramètres de l'appel) est omis.
Le fait que les paramètres de l'appel ne sont pas évalués est bien documenté, car c'est une des raisons les gens à utiliser cette fonction plutôt que d' #if
directives dans le corps de la fonction. La partie sur "l'évaluation du récepteur", cependant, est que je n'arrive pas à trouver ailleurs, et il ne semble pas expliquer ce comportement.
À la lumière de cela, ma question est: quelle est la logique derrière le compilateur C# ne pas évaluer a.GetB()
dans cette situation? Faut-il vraiment se comporter de façon différente selon que le récepteur de l'appel conditionnel est stocké dans une variable temporaire ou pas?