C# 경고 웨이브
C# 컴파일러의 각 릴리스에는 새로운 경고 및 오류가 도입될 수 있습니다. 기존 코드에 대해 새로운 경고가 보고될 수 있는 경우 해당 경고는 경고 웨이브라고 하는 옵트인 시스템에 도입됩니다. 옵트인 시스템은 이를 사용하도록 설정하기 위한 조치를 취하지 않으면 기존 코드에 대한 새로운 경고가 표시되어서는 안 된다는 것을 의미합니다. 경고 웨이브는 프로젝트 파일의 AnalyticLevel 요소를 사용하여 사용하도록 설정됩니다. <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
가 지정된 경우 사용하도록 설정된 경고 웨이브 경고는 오류를 생성합니다. 경고 웨이브 5 진단이 C# 9에 추가되었습니다. 경고 웨이브 6 진단이 C# 10에 추가되었습니다. 경고 웨이브 7 진단이 C# 11에 추가되었습니다. 경고 웨이브 8 진단이 C# 12에 추가되었습니다.
CS9123 - 비동기 메서드에서 로컬 또는 매개 변수의 주소를 가져오면 GC 홀이 만들어질 수 있습니다.
경고 웨이브 8
비동기 메서드의 매개 변수나 지역 변수에 &
연산자를 사용하면 안 됩니다.
다음 코드는 CS9123을 생성합니다.
public static async Task LogValue()
{
int x = 1;
unsafe {
int* y = &x;
Console.WriteLine(*y);
}
await Task.Delay(1000);
}
C# 13부터 이 코드는 컴파일러 오류를 생성합니다.
CS8981 - 형식 이름에는 소문자 ASCII 문자만 포함됩니다.
경고 웨이브 7
C#에 추가된 새 키워드는 모두 소문자 ASCII 문자입니다. 이 경고는 사용자의 형식이 향후 키워드와 충돌하지 않도록 보장합니다. 다음 코드는 CS8981을 생성합니다.
public class lowercasename
{
}
대문자, 숫자, 밑줄 등 소문자 이외의 ASCII 문자를 하나 이상 포함하도록 형식 이름을 변경하여 이 경고를 해결할 수 있습니다.
CS8826 - partial 메서드 선언에는 서명 차이가 있습니다.
경고 웨이브 6
이 경고는 partial 메서드 서명 간의 차이점을 보고할 때 발생하는 일부 불일치를 수정합니다. partial 메서드 서명이 다른 CLR 서명을 만들면 컴파일러는 항상 오류를 보고했습니다. 이제 컴파일러는 서명이 구문적으로 다른 C#인 경우 CS8826을 보고합니다. 다음 partial 클래스를 고려합니다.
public partial class PartialType
{
public partial void M1(int x);
public partial T M2<T>(string s) where T : struct;
public partial void M3(string s);
public partial void M4(object o);
public partial void M5(dynamic o);
public partial void M6(string? s);
}
다음 partial 클래스 구현은 CS8626의 여러 예를 생성합니다.
public partial class PartialType
{
// Different parameter names:
public partial void M1(int y) { }
// Different type parameter names:
public partial TResult M2<TResult>(string s) where TResult : struct => default;
// Relaxed nullability
public partial void M3(string? s) { }
// Mixing object and dynamic
public partial void M4(dynamic o) { }
// Mixing object and dynamic
public partial void M5(object o) { }
// Note: This generates CS8611 (nullability mismatch) not CS8826
public partial void M6(string s) { }
}
참고 항목
다른 선언이 null 허용 참조 형식을 허용하는 경우 메서드 구현에서 null을 허용하지 않는 참조 형식을 사용하는 경우 CS8826 대신 CS8611이 생성됩니다.
이러한 경고의 인스턴스를 수정하려면 두 서명이 일치하는지 확인합니다.
CS7023 - 'is' 또는 'as' 식에 정적 형식이 사용됩니다.
경고 단계 5
정적 형식의 인스턴스를 만들 수 없기 때문에 is
및 as
식은 항상 정적 형식에 대해 false
를 반환합니다. 다음 코드는 CS7023을 생성합니다.
static class StaticClass
{
public static void Thing() { }
}
void M(object o)
{
// warning: cannot use a static type in 'is' or 'as'
if (o is StaticClass)
{
Console.WriteLine("Can't happen");
}
else
{
Console.WriteLine("o is not an instance of a static class");
}
}
형식 테스트는 결코 성공할 수 없기 때문에 컴파일러는 이 경고를 보고합니다. 이 경고를 수정하려면 테스트를 제거하고 테스트가 성공한 경우에만 실행되는 모든 코드를 제거합니다. 앞의 예에서는 else
절이 항상 실행됩니다. 해당 메서드 본문을 해당 한 줄로 바꿀 수 있습니다.
Console.WriteLine("o is not an instance of a static class");
CS8073 - 식의 결과는 항상 'false'(또는 'true')입니다.
경고 단계 5
==
및 !=
연산자는 struct
형식의 인스턴스를 null
과 비교할 때 항상 false
(또는 true
)를 반환합니다. 다음 코드는 이 경고를 보여 줍니다. S
은(는) operator ==
및 operator !=
을(를) 정의하는 struct
(으)로 가정합니다.
class Program
{
public static void M(S s)
{
if (s == null) { } // CS8073: The result of the expression is always 'false'
if (s != null) { } // CS8073: The result of the expression is always 'true'
}
}
struct S
{
public static bool operator ==(S s1, S s2) => s1.Equals(s2);
public static bool operator !=(S s1, S s2) => !s1.Equals(s2);
public override bool Equals(object? other)
{
// Implementation elided
return false;
}
public override int GetHashCode() => 0;
// Other details elided...
}
이 오류를 수정하려면 개체가 null
인 경우 실행되는 Null 검사와 코드를 제거합니다.
CS8848 - 우선 순위로 인해 여기서 'from' 연산자를 사용할 수 없습니다. 명확하게 하려면 괄호를 사용합니다.
경고 단계 5
다음 예에서는 이 경고를 보여 줍니다. 연산자의 우선 순위로 인해 식이 잘못 바인딩되었습니다.
bool b = true;
var source = new Src();
b = true;
source = new Src();
var a = b && from c in source select c;
Console.WriteLine(a);
var indexes = new Src2();
int[] array = { 1, 2, 3, 4, 5, 6, 7 };
var range = array[0..from c in indexes select c];
이 오류를 해결하려면 쿼리 식 주위에 괄호를 넣으세요.
bool b = true;
var source = new Src();
b = true;
source = new Src();
var a = b && (from c in source select c);
Console.WriteLine(a);
var indexes = new Src2();
int[] array = { 1, 2, 3, 4, 5, 6, 7 };
var range = array[0..(from c in indexes select c)];
멤버는 완전히 할당되어야 합니다. 할당되지 않은 변수 사용(CS8880, CS8881, CS8882, CS8883, CS8884, CS8885, CS8886, CS8887)
경고 단계 5
여러 경고는 가져온 어셈블리에 선언된 struct
형식에 대한 명확한 할당 분석을 개선합니다. 다음 예와 같이 가져온 어셈블리의 구조체에 참조 형식의 액세스할 수 없는 필드(일반적으로 private
필드)가 포함된 경우 이러한 새로운 경고가 모두 생성됩니다.
public struct Struct
{
private string data = String.Empty;
public Struct() { }
}
다음 예에서는 개선된 한정 할당 분석에서 생성된 경고를 보여 줍니다.
- CS8880: 제어가 호출자에게 반환되기 전에 자동 구현 속성 'Property'를 완전히 할당해야 합니다.
- CS8881: 제어권이 호출자에게 반환되기 전에 'field' 필드를 완전히 할당해야 합니다.
- CS8882: 제어가 현재 메서드를 벗어나기 전에 'parameter' out 매개 변수를 할당해야 합니다.
- CS8883: 할당되지 않은 자동 구현 속성 'Property'를 사용합니다.
- CS8884: 할당되지 않은 필드 'Field'를 사용합니다.
- CS8885: 모든 필드가 할당되기 전에는 'this' 개체를 사용할 수 없습니다.
- CS8886: 할당되지 않은 출력 매개 변수 'parameterName'을 사용합니다.
- CS8887: 할당되지 않은 지역 변수 'variableName' 사용합니다.
public struct DefiniteAssignmentWarnings
{
// CS8880
public Struct Property { get; }
// CS8881
private Struct field;
// CS8882
public void Method(out Struct s)
{
}
public DefiniteAssignmentWarnings(int dummy)
{
// CS8883
Struct v2 = Property;
// CS8884
Struct v3 = field;
// CS8885:
DefiniteAssignmentWarnings p2 = this;
}
public static void Method2(out Struct s1)
{
// CS8886
var s2 = s1;
s1 = default;
}
public static void UseLocalStruct()
{
Struct r1;
var r2 = r1;
}
}
가져온 구조체를 기본값으로 초기화하거나 할당하여 이러한 경고를 수정할 수 있습니다.
public struct DefiniteAssignmentNoWarnings
{
// CS8880
public Struct Property { get; } = default;
// CS8881
private Struct field = default;
// CS8882
public void Method(out Struct s)
{
s = default;
}
public DefiniteAssignmentNoWarnings(int dummy)
{
// CS8883
Struct v2 = Property;
// CS8884
Struct v3 = field;
// CS8885:
DefiniteAssignmentNoWarnings p2 = this;
}
public static void Method2(out Struct s1)
{
// CS8886
s1 = default;
var s2 = s1;
}
public static void UseLocalStruct()
{
Struct r1 = default;
var r2 = r1;
}
}
CS8892 - 동기 진입점 ‘method’를 찾았으므로 메서드가 진입점으로 사용되지 않습니다.
경고 단계 5
이 경고는 하나 이상의 동기 진입점을 포함하여 유효한 진입점이 여러 개인 경우 모든 비동기 진입점 후보에 대해 생성됩니다.
다음 예에서는 CS8892를 생성합니다.
public static void Main()
{
RunProgram();
}
// CS8892
public static async Task Main(string[] args)
{
await RunProgramAsync();
}
참고 항목
컴파일러는 항상 동기 진입점을 사용합니다. 동기 진입점이 여러 개인 경우 컴파일러 오류가 발생합니다.
이 경고를 해결하려면 비동기 진입점을 제거하거나 이름을 바꿉니다.
CS8897 - 정적 형식을 매개 변수로 사용할 수 없습니다.
경고 단계 5
인터페이스 멤버는 형식이 정적 클래스인 매개 변수를 선언할 수 없습니다. 다음 코드는 CS8897과 CS8898을 모두 보여 줍니다.
public static class Utilities
{
// elided
}
public interface IUtility
{
// CS8897
public void SetUtility(Utilities u);
// CS8898
public Utilities GetUtility();
}
이 경고를 해결하려면 매개 변수 형식을 변경하거나 메서드를 제거합니다.
CS8898 - 정적 형식을 반환 형식으로 사용할 수 없습니다.
경고 단계 5
인터페이스 멤버는 정적 클래스인 반환 형식을 선언할 수 없습니다. 다음 코드는 CS8897과 CS8898을 모두 보여 줍니다.
public static class Utilities
{
// elided
}
public interface IUtility
{
// CS8897
public void SetUtility(Utilities u);
// CS8898
public Utilities GetUtility();
}
이 경고를 해결하려면 반환 형식을 변경하거나 메서드를 제거합니다.
.NET