디스카드는 애플리케이션 코드에서 의도적으로 사용되지 않는 자리 표시자 변수입니다. 폐기 변수는 할당되지 않은 변수와 동일하며, 값이 없습니다. 버림은 컴파일러와 코드를 읽는 다른 사람들에게 당신의 의도를 전달합니다: 식의 결과를 의도적으로 무시하려는 것이었습니다. 식의 결과, 하나 이상의 튜플 식 멤버, 메서드에 대한 out
매개 변수 또는 패턴 일치 식의 대상을 무시할 수 있습니다.
삭제하면 코드의 의도가 명확해집니다. 폐기는 코드에서 변수를 결코 사용하지 않는다는 것을 나타냅니다. 가독성 및 유지 관리를 향상시킵니다.
변수는 밑줄(_
)을 해당 이름으로 할당하여 무시됨을 나타냅니다. 예를 들어 다음 메서드 호출은 첫 번째 및 두 번째 값이 무시되는 튜플을 반환합니다.
area
는 GetCityInformation
이 반환한 세 번째 구성 요소로 구성된 이전에 선언된 변수들의 집합입니다.
(_, _, area) = city.GetCityInformation(cityName);
무시를 사용하여 람다 식의 사용되지 않는 입력 매개 변수를 지정할 수 있습니다. 자세한 내용은 람다 식 문서의 람다 식 섹션의 입력 매개 변수 를 참조 하세요 .
유효한 삭제인 경우 _
해당 값을 검색하거나 할당 작업에서 사용하려고 하면 컴파일러 오류 CS0103, "이름 '_'이(가) 현재 컨텍스트에 없습니다."가 생성됩니다. 이 오류는 값이 할당되지 않았고 스토리지 위치도 할당되지 않을 수 있기 때문 _
입니다. 실제 변수인 경우 이전 예제와 같이 둘 이상의 값을 삭제할 수 없습니다.
튜플 및 객체 분해
삭제는 애플리케이션 코드에서 일부 튜플 요소를 사용하지만 다른 요소를 무시하는 경우 튜플 작업에 유용합니다. 예를 들어 다음 메서드는 QueryCityDataForYears
도시 이름, 해당 지역, 1년, 해당 연도의 도시 인구, 2년차 및 해당 2년 동안의 도시 인구가 포함된 튜플을 반환합니다. 이 예제는 이러한 두 연도 사이의 인구 변화를 보여 줍니다. 튜플에서 사용 가능한 데이터 중 도시 면적에는 관심이 없고 디자인 타임에 도시 이름과 두 날짜를 알고 있습니다. 따라서 튜플에 저장된 두 가지 인구 값에만 관심이 있고 나머지 값은 무시 항목으로 처리할 수 있습니다.
var (_, _, _, pop1, _, pop2) = QueryCityDataForYears("New York City", 1960, 2010);
Console.WriteLine($"Population change, 1960 to 2010: {pop2 - pop1:N0}");
static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int year2)
{
int population1 = 0, population2 = 0;
double area = 0;
if (name == "New York City")
{
area = 468.48;
if (year1 == 1960)
{
population1 = 7781984;
}
if (year2 == 2010)
{
population2 = 8175133;
}
return (name, area, year1, population1, year2, population2);
}
return ("", 0, 0, 0, 0, 0);
}
// The example displays the following output:
// Population change, 1960 to 2010: 393,149
삭제 변수를 사용하여 튜플을 분해하는 방법에 대한 자세한 내용은 튜플 및 기타 형식의 분해를 확인하십시오.
Deconstruct
클래스, 구조 또는 인터페이스의 메서드를 사용하면 개체에서 특정 데이터 집합을 검색하고 분해할 수도 있습니다. 분해된 값의 하위 집합만 사용하려는 경우 삭제를 사용할 수 있습니다. 다음 예제에서는 개체를 Person
네 개의 문자열(이름 및 성, 도시 및 주)으로 분해하지만 성 및 상태를 삭제합니다.
using System;
namespace Discards
{
public class Person
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public string State { get; set; }
public Person(string fname, string mname, string lname,
string cityName, string stateName)
{
FirstName = fname;
MiddleName = mname;
LastName = lname;
City = cityName;
State = stateName;
}
// Return the first and last name.
public void Deconstruct(out string fname, out string lname)
{
fname = FirstName;
lname = LastName;
}
public void Deconstruct(out string fname, out string mname, out string lname)
{
fname = FirstName;
mname = MiddleName;
lname = LastName;
}
public void Deconstruct(out string fname, out string lname,
out string city, out string state)
{
fname = FirstName;
lname = LastName;
city = City;
state = State;
}
}
class Example
{
public static void Main()
{
var p = new Person("John", "Quincy", "Adams", "Boston", "MA");
// Deconstruct the person object.
var (fName, _, city, _) = p;
Console.WriteLine($"Hello {fName} of {city}!");
// The example displays the following output:
// Hello John of Boston!
}
}
}
자세한 내용을 보려면 버리기를 사용하여 사용자 정의 형식을 분해하는 방법에 대해 튜플 및 기타 형식 분해를 참조하세요.
switch
와 패턴 일치
무시 패턴은 패턴 매칭에서 switch 식과 함께 사용할 수 있습니다. 을 비롯한 null
모든 식은 항상 무시 패턴과 일치합니다.
다음 예제에서는 ProvidesFormatInfo
메서드를 정의합니다. 이 메서드는 switch
표현식을 사용하여 개체가 IFormatProvider 구현을 제공하는지 여부를 확인하고, 개체가 null
인지 테스트합니다. 또한 무시 패턴을 사용하여 다른 형식의 null이 아닌 개체를 처리합니다.
object?[] objects = [CultureInfo.CurrentCulture,
CultureInfo.CurrentCulture.DateTimeFormat,
CultureInfo.CurrentCulture.NumberFormat,
new ArgumentException(), null];
foreach (var obj in objects)
ProvidesFormatInfo(obj);
static void ProvidesFormatInfo(object? obj) =>
Console.WriteLine(obj switch
{
IFormatProvider fmt => $"{fmt.GetType()} object",
null => "A null object reference: Its use could result in a NullReferenceException",
_ => "Some object type without format information"
});
// The example displays the following output:
// System.Globalization.CultureInfo object
// System.Globalization.DateTimeFormatInfo object
// System.Globalization.NumberFormatInfo object
// Some object type without format information
// A null object reference: Its use could result in a NullReferenceException
매개 변수를 사용하여 메서드 out
호출
메서드를 Deconstruct
호출하여 사용자 정의 형식(클래스, 구조 또는 인터페이스의 인스턴스)을 분해할 때 개별 out
인수의 값을 삭제할 수 있습니다. 그러나 매개 변수가 out
인 메서드를 호출할 때 out
인수의 값을 무시할 수도 있습니다.
다음 예제에서는 DateTime.TryParse(String, out DateTime) 메서드를 호출하여 날짜의 문자열 표현이 현재 문화권에서 유효한지 여부를 확인합니다. 이 예제는 날짜 문자열의 유효성 검사와 날짜를 추출하기 위한 구문 분석과 관련이 없으므로 메서드에 out
대한 인수는 무시됩니다.
string[] dateStrings = ["05/01/2018 14:57:32.8", "2018-05-01 14:57:32.8",
"2018-05-01T14:57:32.8375298-04:00", "5/01/2018",
"5/01/2018 14:57:32.80 -07:00",
"1 May 2018 2:57:32.8 PM", "16-05-2018 1:00:32 PM",
"Fri, 15 May 2018 20:10:57 GMT"];
foreach (string dateString in dateStrings)
{
if (DateTime.TryParse(dateString, out _))
Console.WriteLine($"'{dateString}': valid");
else
Console.WriteLine($"'{dateString}': invalid");
}
// The example displays output like the following:
// '05/01/2018 14:57:32.8': valid
// '2018-05-01 14:57:32.8': valid
// '2018-05-01T14:57:32.8375298-04:00': valid
// '5/01/2018': valid
// '5/01/2018 14:57:32.80 -07:00': valid
// '1 May 2018 2:57:32.8 PM': valid
// '16-05-2018 1:00:32 PM': invalid
// 'Fri, 15 May 2018 20:10:57 GMT': invalid
독립형 폐기
독립 실행형 무시를 사용하여 무시하도록 선택한 변수를 나타낼 수 있습니다. 한 가지 일반적인 용도는 인수가 null이 아닌지 확인하기 위해 할당을 사용하는 것입니다. 다음 코드에서는 할당을 수행하기 위해 삭제를 사용합니다. 할당의 오른쪽은 null 병합 연산자를 사용하여 인수가 System.ArgumentNullException일 때 null
을 throw합니다. 코드는 할당 결과가 필요하지 않으므로 삭제됩니다. 식은 null 검사를 강제로 실행합니다. 삭제는 사용자의 의도를 명확히 합니다. 할당 결과가 필요하거나 사용되지 않습니다.
public static void Method(string arg)
{
_ = arg ?? throw new ArgumentNullException(paramName: nameof(arg), message: "arg can't be null");
// Do work with arg.
}
다음 예제에서는 비동기 작업에서 반환된 Task 개체를 무시하기 위해 독립 실행형 삭제를 사용합니다. 작업을 할당하면 작업이 완료되려는 순간 throw되는 예외를 억제하는 효과가 있습니다. 의도를 명확히 합니다. 비동기 작업에서 생성된 오류를 무시하고 Task
삭제하려고 합니다.
private static async Task ExecuteAsyncMethods()
{
Console.WriteLine("About to launch a task...");
_ = Task.Run(() =>
{
var iterations = 0;
for (int ctr = 0; ctr < int.MaxValue; ctr++)
iterations++;
Console.WriteLine("Completed looping operation...");
throw new InvalidOperationException();
});
await Task.Delay(5000);
Console.WriteLine("Exiting after 5 second delay");
}
// The example displays output like the following:
// About to launch a task...
// Completed looping operation...
// Exiting after 5 second delay
discard에 작업을 할당하지 않으면, 아래 코드가 컴파일러 경고를 발생시킵니다.
private static async Task ExecuteAsyncMethods()
{
Console.WriteLine("About to launch a task...");
// CS4014: Because this call is not awaited, execution of the current method continues before the call is completed.
// Consider applying the 'await' operator to the result of the call.
Task.Run(() =>
{
var iterations = 0;
for (int ctr = 0; ctr < int.MaxValue; ctr++)
iterations++;
Console.WriteLine("Completed looping operation...");
throw new InvalidOperationException();
});
await Task.Delay(5000);
Console.WriteLine("Exiting after 5 second delay");
비고
디버거를 사용하여 위의 두 샘플 중 하나를 실행하는 경우 예외가 throw되면 디버거가 프로그램을 중지합니다. 디버거를 연결하지 않으면 두 경우 모두 예외가 자동으로 무시됩니다.
_
은 유효한 식별자이기도 합니다. 지원되는 컨텍스트 _
외부에서 사용되는 경우 무시가 아니라 유효한 변수로 처리됩니다. 식별자 _
가 이미 범위에 있는 경우 독립형 폐기로 _
을/를 사용하면 다음이 발생할 가능성이 있습니다.
- 실수로 범위 내
_
변수의 값을 의도된 버림 값으로 할당하여 수정했습니다. 다음은 그 예입니다.private static void ShowValue(int _) { byte[] arr = [0, 0, 1, 2]; _ = BitConverter.ToInt32(arr, 0); Console.WriteLine(_); } // The example displays the following output: // 33619968
- 형식 안전성 위반에 대한 컴파일러 오류입니다. 다음은 그 예입니다.
private static bool RoundTrips(int _) { string value = _.ToString(); int newValue = 0; _ = Int32.TryParse(value, out newValue); return _ == newValue; } // The example displays the following compiler error: // error CS0029: Cannot implicitly convert type 'bool' to 'int'
참고하십시오
.NET