이것은 프로그래밍 과정에서 우리 팀원 중 한 명이 제기한 질문입니다. 이 컴파일 오류는 피하기 쉽기 때문에 그의 코드를 보고 이 문제가 그렇게 간단하지 않다는 것을 깨닫기 전까지는 이 문제에 대해 신중하게 생각해 본 적이 없습니다.
먼저 이 코드를 살펴보세요.
암호
수업 프로그램
{
정적 무효 Main(string[] args)
{
바이트[] buf = 새 바이트[1024];
Tt = 새로운 T();
문자열 str = "1234";
정수 n = 1234;
int?nn = 1234;
DateTime dt = DateTime.Now;
객체 o = 1234;
Console.WriteLine("마침");
}
}
클래스 T { }
이 코드에서 사용되지 않은 변수는 몇 개라고 생각하시나요?
프로그래머의 관점에서 보면 모든 변수가 사용되지 않는다는 것이 답이 될 것입니다. 그러나 컴파일러가 제공한 결과는 약간 반직관적입니다.
변수 "str"에 값이 할당되었지만 해당 값이 사용된 적이 없습니다. 변수 "n"에 값이 할당되었지만 해당 값이 사용된 적이 없습니다. 값은 한번도 사용되지 않았습니다.
이상한 점은 모든 변수가 같은 방식으로 선언되었음에도 불구하고 컴파일러는 그 중 일부가 사용되지 않은 것으로만 생각한다는 것입니다. 무슨 일이야?
하나씩 분석해 보겠습니다. 먼저 배열을 살펴보십시오. 기본값이 사용되면 컴파일러에서 제공하는 정보가 다릅니다.
byte[] buf1 = null; // 경고가 있습니다.
byte[] buf2 = new byte[1024]; // 경고 없음
이 결과는 매개변수 할당이 null인 경우 컴파일러가 실제로 할당을 수행하지 않고 변수가 사용되지 않은 것처럼 처리된다는 것을 나타내는 것으로 보입니다. IL 검사 결과도 이 진술을 증명할 수 있습니다. 첫 번째 라인의 경우 컴파일러는 두 번째 라인의 해당 명령문을 생성하지 않았으며 newattr 명령을 사용하여 배열을 생성했습니다.
사용자 정의 클래스의 경우:
T t1 = null; // 경고가 있습니다.
T t2 = new T(); // 경고 없음
이 결과는 이해할 수 있어야 합니다(이해할 수는 있지만 아래 이유 때문에 좋지 않다고 생각합니다). 클래스의 메서드를 호출하지는 않지만 클래스 생성자는 여전히 일부 작업을 수행할 수 있으므로 클래스가 생성되는 한 컴파일러는 이를 마치 사용된 것처럼 처리합니다.
기본 값 유형의 경우 해당 동작은 참조 유형과 다릅니다. 컴파일러는 초기 할당을 변수 사용으로 처리하지 않습니다.
int n1 = 0; // 경고가 있습니다.
int n2 = 1234; // 경고가 있습니다.
int?n3 = null; // 경고가 있습니다.
int?n4 = 0; // 경고가 있습니다.
int?n5 = 1234; // 경고가 있습니다.
String은 구현상 참조타입으로 간주해야 하지만, 성능은 값타입에 더 가깝고, 경고정보도 값타입과 동일합니다.
약간 더 복잡한 값 유형의 경우 결과는 좀 더 미묘합니다.
DateTime dt1; // 경고가 있습니다.
DateTime dt2 = new DateTime(); // 경고가 있습니다.
DateTime dt3 = new DateTime(2009,1,1); // 경고 없음
DateTime dt4 = DateTime.Now // 경고 없음;
이번 결과에서 주목할 점이 하나 있다. DateTime의 기본 생성자와 매개변수화된 생성자는 모두 사용자 관점에서는 생성자이지만 컴파일러 관점에서는 다릅니다. 또한 IL을 사용하여 디컴파일하면 기본 생성자가 호출되면 컴파일러는 initobj 명령어를 호출하고 호출 ctor 명령어는 매개변수화된 생성자에 사용되는 것을 볼 수 있습니다. 또한 프로그래머의 관점에서는 할당 코드의 형식이 정확히 동일하더라도 컴파일러는 할당된 값에 따라 다른 구성 전략을 채택하게 되는데, 이는 또한 직관에 어긋납니다.
최종 결론은 유감스럽습니다. 즉, C#의 컴파일 경고만으로는 프로그래머에게 특히 배열에 대한 충분한 보호를 제공하기에 충분하지 않습니다.
바이트[] buf = 새 바이트[1024];
이러한 배열을 사용하지 않고 구성만 하면 컴파일러는 프로그래머에게 경고 메시지를 표시하지 않습니다.
고려해야 할 또 다른 문제는 다음과 같은 메소드를 사용하지 않고 클래스를 선언하는 것입니다.
Tt = 새로운 T()
이것이 합리적인 행동인가? 컴파일러는 이에 대해 경고를 발행해야 합니까?
내 개인적인 의견은 사용법 관점에서 볼 때 이는 불합리하며 가능한 한 피해야 한다는 것입니다. 컴파일러는 이러한 사용법을 발견하면 경고를 발행해야 합니다. 필요한 경우 컴파일 지시문이나 Attribute 메서드를 통해 구체적으로 선언하여 경고 메시지를 피할 수 있습니다. 그러나 C# 컴파일러의 동작은 경고를 발행하지 않는 것이므로 저는 이에 동의하지 않습니다. 물론, 모두가 자신의 생각을 내놓기를 바랍니다.