Dies ist eine Frage, die eines unserer Teammitglieder während des Programmierprozesses gestellt hat. Da dieser Kompilierungsfehler leicht zu vermeiden ist, habe ich nie sorgfältig über dieses Problem nachgedacht, bis ich mir seinen Code angesehen habe und festgestellt habe, dass dieses Problem nicht so einfach ist.
Schauen Sie sich zuerst diesen Code an:
Code
Klassenprogramm
{
static void Main(string[] args)
{
byte[] buf = neues Byte[1024];
T t = neues T();
string str = "1234";
int n = 1234;
int?nn = 1234;
DateTime dt = DateTime.Now;
Objekt o = 1234;
Console.WriteLine("finish");
}
}
Klasse T { }
Wie viele Variablen werden Ihrer Meinung nach in diesem Code nicht verwendet?
Wenn man es aus der Perspektive eines Programmierers betrachtet, sollte die Antwort lauten, dass alle Variablen ungenutzt sind. Das vom Compiler ausgegebene Ergebnis ist jedoch etwas kontraintuitiv:
Der Variablen „str“ wurde ein Wert zugewiesen, aber ihr Wert wurde nie verwendet. Der Variable „n“ wurde ein Wert zugewiesen, aber ihr Wert wurde nie verwendet Der Wert wurde nie verwendet.
Das Merkwürdige ist, dass der Compiler nur denkt, dass einige davon ungenutzt sind, obwohl alle Variablen auf die gleiche Weise deklariert sind. Was ist los?
Lassen Sie uns sie einzeln analysieren. Schauen Sie sich zunächst das Array an. Wenn der Standardwert verwendet wird, sind die vom Compiler bereitgestellten Informationen unterschiedlich:
byte[] buf1 = null; // Es liegt eine Warnung vor
byte[] buf2 = neues Byte[1024]; // keine Warnung
Dieses Ergebnis scheint darauf hinzudeuten, dass der Compiler die Zuweisung nicht tatsächlich ausführt, wenn die Parameterzuweisung null ist, und die Variable so behandelt wird, als ob sie nicht verwendet worden wäre. Auch die Ergebnisse der IL-Inspektion können diese Aussage belegen: Für die erste Zeile hat der Compiler keine entsprechende Anweisung generiert, für die zweite Zeile wurde die newattr-Anweisung zum Erstellen des Arrays verwendet.
Für benutzerdefinierte Klassen:
T t1 = null; // Es liegt eine Warnung vor
T t2 = new T(); // keine Warnung
Dieses Ergebnis sollte verständlich sein (obwohl es verständlich ist, halte ich es aus den unten aufgeführten Gründen nicht für gut). Obwohl wir keine Methoden der Klasse aufrufen, führt der Konstruktor der Klasse möglicherweise dennoch einige Vorgänge aus. Solange eine Klasse erstellt wird, behandelt der Compiler sie so, als ob sie verwendet worden wäre.
Bei Basiswerttypen unterscheidet sich ihr Verhalten von Referenztypen. Der Compiler behandelt die anfängliche Zuweisung nicht als Verwendung von Variablen:
int n1 = 0; // Es liegt eine Warnung vor
int n2 = 1234; // Es liegt eine Warnung vor
int? n3 = null; // Es liegt eine Warnung vor
int? n4 = 0; // Es liegt eine Warnung vor
int? n5 = 1234; // Es liegt eine Warnung vor
String sollte im Hinblick auf die Implementierung als Referenztyp betrachtet werden, seine Leistung ähnelt jedoch eher einem Werttyp und die Warninformationen sind dieselben wie die eines Werttyps.
Bei etwas komplexeren Werttypen sind die Ergebnisse etwas subtiler:
DateTime dt1; // Es liegt eine Warnung vor
DateTime dt2 = new DateTime(); // Es liegt eine Warnung vor
DateTime dt3 = new DateTime(2009,1,1); // keine Warnung
DateTime dt4 = DateTime.Now; // keine Warnung
Zu diesem Ergebnis ist eines zu beachten. Obwohl der Standardkonstruktor und der parametrisierte Konstruktor von DateTime aus Sicht des Benutzers beide Konstruktoren sind, unterscheiden sie sich aus Sicht des Compilers. Durch die Dekompilierung mit IL lässt sich auch erkennen, dass der Compiler beim Aufruf des Standardkonstruktors die Initobj-Anweisung aufruft, während die Call-Ctor-Anweisung für den parametrisierten Konstruktor verwendet wird. Obwohl das Format des Zuweisungscodes aus Sicht des Programmierers genau das gleiche ist, wendet der Compiler außerdem je nach zugewiesenem Wert unterschiedliche Konstruktionsstrategien an, was ebenfalls nicht intuitiv ist.
Die abschließende Schlussfolgerung ist bedauerlich, dass die Kompilierungswarnungen von C# nicht ausreichen, um Programmierern ausreichenden Schutz zu bieten, insbesondere für Arrays:
byte[] buf = neues Byte[1024];
Wenn Sie ein solches Array nur erstellen, ohne es zu verwenden, gibt der Compiler dem Programmierer keine Warnmeldung.
Ein weiterer erwägenswerter Punkt ist die Deklaration einer Klasse ohne die Verwendung von Methoden, wie z. B. just
T t = neues T()
Ist das vernünftiges Verhalten? Sollte der Compiler hierfür eine Warnung ausgeben?
Meiner persönlichen Meinung nach ist dies aus Nutzungssicht unvernünftig und sollte so weit wie möglich vermieden werden. Der Compiler sollte eine Warnung ausgeben, wenn er diese Verwendung entdeckt. Bei Bedarf können Sie Warnmeldungen vermeiden, indem Sie sie gezielt über Kompilierungsanweisungen oder Attributmethoden deklarieren. Allerdings gibt der C#-Compiler keine Warnungen aus, womit ich nicht einverstanden bin. Natürlich hoffe ich auch, dass jeder seine eigenen Ideen einbringt.