학습
C#의 메서드
메서드는 일련의 문을 포함하는 코드 블록입니다. 프로그램을 통해 메서드를 호출하고 필요한 메서드 인수를 지정하여 문을 실행합니다. C#에서는 실행된 모든 명령이 메서드의 컨텍스트에서 수행됩니다.
참고
이 항목에서는 명명된 메서드에 대해 설명합니다. 무명 기능에 대한 자세한 내용은 람다 식을 참조하세요.
메서드는 다음을 지정하여 class
, record
, struct
에서 선언됩니다.
-
public
또는private
와 같은 선택적 액세스 수준입니다. 기본값은private
입니다. -
abstract
또는sealed
와 같은 선택적 한정자입니다. - 반환 값 또는 메서드에 반환 값이 없는 경우
void
입니다. - 메서드 이름입니다.
- 메서드 매개 변수입니다. 메서드 매개 변수는 괄호로 묶고 쉼표로 구분합니다. 빈 괄호는 메서드에 매개 변수가 필요하지 않음을 나타냅니다.
이러한 부분이 결합되어 메서드 시그니처를 구성합니다.
중요
메서드의 반환 값은 메서드 오버로드를 위한 메서드 서명의 파트가 아닙니다. 그러나 대리자와 대리자가 가리키는 메서드 간의 호환성을 결정할 경우에는 메서드 서명의 부분입니다.
다음 예제에서는 다섯 개의 메서드를 포함하는 Motorcycle
이라는 클래스를 정의합니다.
namespace MotorCycleExample
{
abstract class Motorcycle
{
// Anyone can call this.
public void StartEngine() {/* Method statements here */ }
// Only derived classes can call this.
protected void AddGas(int gallons) { /* Method statements here */ }
// Derived classes can override the base class implementation.
public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }
// Derived classes can override the base class implementation.
public virtual int Drive(TimeSpan time, int speed) { /* Method statements here */ return 0; }
// Derived classes must implement this.
public abstract double GetTopSpeed();
}
Motorcycle
클래스에는 오버로드된 메서드 Drive
(이)가 포함됩니다. 두 메서드는 이름이 같지만 각자의 매개 변수 형식으로 구별됩니다.
메서드는 인스턴스 또는 정적일 수 있습니다. 해당 인스턴스에서 인스턴스 메서드를 호출하려면 개체를 인스턴스화해야 합니다. 인스턴스 메서드는 해당 인스턴스와 해당 데이터에 대해 작동합니다. 메서드가 속한 형식의 이름을 참조하여 정적 메서드를 호출합니다. 정적 메서드는 인스턴스 데이터에서 작동하지 않습니다. 개체 인스턴스를 통해 정적 메서드를 호출하려고 하면 컴파일러 오류가 생성됩니다.
메서드 호출은 필드 액세스와 비슷합니다. 개체 이름(인스턴스 메서드를 호출하는 경우) 또는 형식 이름(static
메서드를 호출하는 경우) 다음 마침표, 메서드 이름 및 괄호를 추가합니다. 인수는 괄호 안에 나열되고 쉼표로 구분됩니다.
메서드 정의는 필요한 모든 매개 변수의 이름 및 형식을 지정합니다. 호출자는 메서드를 호출할 때 각 매개 변수에 대해 인수라는 구체적인 값을 제공합니다. 인수는 매개 변수 형식과 호환되어야 하지만 호출 코드에서 인수 이름을 사용하는 경우 메서드에 정의된 명명된 매개 변수와 같을 필요는 없습니다. 다음 예제에서는 Square
메서드에 int
라는 형식의 단일 매개 변수가 포함되어 있습니다. 첫 번째 메서드 호출은 Square
메서드에 int
이라는 형식의 변수를 전달합니다. 두 번째 호출은 숫자 상수, 세 번째 호출은 식을 전달합니다.
public static class SquareExample
{
public static void Main()
{
// Call with an int variable.
int num = 4;
int productA = Square(num);
// Call with an integer literal.
int productB = Square(12);
// Call with an expression that evaluates to int.
int productC = Square(productA * 3);
}
static int Square(int i)
{
// Store input argument in a local variable.
int input = i;
return input * input;
}
}
가장 일반적인 형태의 메서드 호출은 위치 인수를 사용하며, 메서드 매개 변수와 동일한 순서로 인수를 제공합니다.
Motorcycle
클래스의 메서드는 다음 예제와 같이 호출될 수 있습니다. 예를 들어 Drive
메서드 호출에는 메서드 구문의 두 매개 변수에 해당하는 두 개의 인수가 포함되어 있습니다. 첫 번째는 miles
매개 변수의 값이 됩니다. 두 번째는 speed
매개 변수의 값이 됩니다.
class TestMotorcycle : Motorcycle
{
public override double GetTopSpeed() => 108.4;
static void Main()
{
var moto = new TestMotorcycle();
moto.StartEngine();
moto.AddGas(15);
_ = moto.Drive(5, 20);
double speed = moto.GetTopSpeed();
Console.WriteLine("My top speed is {0}", speed);
}
}
메서드를 호출할 때 위치 인수 대신 ‘명명된 인수’를 사용할 수도 있습니다. 명명된 인수를 사용하는 경우 매개 변수 이름 뒤에 콜론(":")과 인수를 지정합니다. 모든 필수 인수가 있기만 하면 메서드의 인수 순서는 중요하지 않습니다. 다음 예제에서는 명명된 인수를 사용하여 TestMotorcycle.Drive
메서드를 호출합니다. 이 예제에서는 명명된 인수가 메서드의 매개 변수 목록과 반대 순서로 전달됩니다.
namespace NamedMotorCycle;
class TestMotorcycle : Motorcycle
{
public override int Drive(int miles, int speed) =>
(int)Math.Round((double)miles / speed, 0);
public override double GetTopSpeed() => 108.4;
static void Main()
{
var moto = new TestMotorcycle();
moto.StartEngine();
moto.AddGas(15);
int travelTime = moto.Drive(miles: 170, speed: 60);
Console.WriteLine("Travel time: approx. {0} hours", travelTime);
}
}
// The example displays the following output:
// Travel time: approx. 3 hours
위치 인수와 명명된 인수 둘 다를 사용하여 메서드를 호출할 수 있습니다. 그러나 명명된 인수가 올바른 위치에 있는 경우에만 명명된 인수 뒤에 위치 인수를 사용할 수 있습니다. 다음 예제에서는 위치 인수 하나와 명명된 인수 하나를 사용하여 이전 예제의 TestMotorcycle.Drive
메서드를 호출합니다.
int travelTime = moto.Drive(170, speed: 55);
형식은 해당 형식에서 명시적으로 정의된 멤버 외에도 기본 클래스에서 정의된 멤버를 상속합니다. 관리되는 형식 시스템의 모든 형식이 직접 또는 간접적으로 Object 클래스에서 상속하므로 모든 형식은 Equals(Object), GetType() 및 ToString()과 같은 해당 멤버를 상속합니다. 다음 예제에서는 Person
클래스를 정의하고, 두 개의 Person
개체를 인스턴스화하고, Person.Equals
메서드를 호출하여 두 개체가 같은지 여부를 확인합니다. 그러나 Equals
메서드는 Person
클래스에 정의되어 있지 않습니다. Object에서 상속됩니다.
public class Person
{
public string FirstName = default!;
}
public static class ClassTypeExample
{
public static void Main()
{
Person p1 = new() { FirstName = "John" };
Person p2 = new() { FirstName = "John" };
Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
}
}
// The example displays the following output:
// p1 = p2: False
형식은 override
키워드를 사용하고 재정의된 메서드에 대한 구현을 제공하여 상속된 멤버를 재정의할 수 있습니다. 메서드 시그니처는 재정의된 메서드의 시그니처와 같아야 합니다. 다음 예제는 Equals(Object) 메서드를 재정의한다는 점을 제외하고 이전 예제와 비슷합니다. 또한 두 메서드가 일치하는 결과를 제공하기 때문에 GetHashCode() 메서드를 재정의합니다.
namespace methods;
public class Person
{
public string FirstName = default!;
public override bool Equals(object? obj) =>
obj is Person p2 &&
FirstName.Equals(p2.FirstName);
public override int GetHashCode() => FirstName.GetHashCode();
}
public static class Example
{
public static void Main()
{
Person p1 = new() { FirstName = "John" };
Person p2 = new() { FirstName = "John" };
Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
}
}
// The example displays the following output:
// p1 = p2: True
C#의 형식은 값 형식 또는 참조 형식입니다. 기본 제공 값 형식의 목록은 형식을 참조하세요. 기본적으로 값 형식과 참조 형식은 둘 다 값으로 메서드에 전달됩니다.
값 형식이 값으로 메서드에 전달되는 경우 개체 자체가 아니라 개체의 복사본이 메서드에 전달됩니다. 따라서 제어가 호출자로 반환될 때 호출된 메서드의 개체 변경 내용은 원래 개체에 영향을 주지 않습니다.
다음 예제에서는 값 형식을 값으로 메서드에 전달하며, 호출된 메서드는 값 형식의 값을 변경하려고 합니다. 값 형식인 int
형식의 변수를 정의하고, 해당 값을 20으로 초기화한 다음 ModifyValue
라는 메서드에 전달하면 이 메서드가 변수의 값을 30으로 변경합니다. 그러나 메서드가 반환될 때는 변수의 값이 변경되지 않습니다.
public static class ByValueExample
{
public static void Main()
{
var value = 20;
Console.WriteLine("In Main, value = {0}", value);
ModifyValue(value);
Console.WriteLine("Back in Main, value = {0}", value);
}
static void ModifyValue(int i)
{
i = 30;
Console.WriteLine("In ModifyValue, parameter value = {0}", i);
return;
}
}
// The example displays the following output:
// In Main, value = 20
// In ModifyValue, parameter value = 30
// Back in Main, value = 20
참조 형식의 개체가 메서드에 값으로 전달되는 경우 개체에 대한 참조가 값으로 전달됩니다. 즉, 메서드는 개체 자체가 아니라 개체의 위치를 나타내는 인수를 수신합니다. 이 참조를 사용하여 개체의 멤버를 변경하는 경우 제어가 호출하는 메서드로 반환될 때 변경 내용이 개체에 반영됩니다. 그러나 메서드에 전달되는 개체를 바꾸면 제어가 호출자로 반환될 때 원래 개체에 영향을 주지 않습니다.
다음 예제에서는 SampleRefType
이라는 클래스(참조 형식)를 정의합니다.
SampleRefType
개체를 인스턴스화하고, 해당 value
필드에 44를 할당한 다음 개체를 ModifyObject
메서드에 전달합니다. 이 예제에서는 기본적으로 메서드에 값으로 인수를 전달하는 이전 예제와 동일한 작업을 수행합니다. 그러나 참조 형식이 사용되므로 결과가 다릅니다. 예제의 출력과 같이 ModifyObject
에서 obj.value
필드에 대해 수정한 내용으로 인해 value
메서드에서 rt
인수의 Main
필드도 33으로 변경됩니다.
public class SampleRefType
{
public int value;
}
public static class ByRefTypeExample
{
public static void Main()
{
var rt = new SampleRefType { value = 44 };
ModifyObject(rt);
Console.WriteLine(rt.value);
}
static void ModifyObject(SampleRefType obj) => obj.value = 33;
}
메서드의 인수 값을 변경하고 제어가 호출하는 메서드로 반환될 때 해당 변경 내용을 반영하려는 경우 참조로 매개 변수를 전달합니다. 참조로 매개 변수를 전달하려면 ref
또는 out
키워드를 사용합니다. 복사를 방지하지만 여전히 in
키워드를 사용하여 수정을 방지하도록 참조로 값을 전달할 수도 있습니다.
다음 예제는 값이 참조로 ModifyValue
메서드에 전달된다는 점을 제외하고 이전 예제와 동일합니다.
ModifyValue
메서드에서 매개 변수의 값을 수정하면 제어가 호출자로 반환될 때 값의 변경 내용이 반영됩니다.
public static class ByRefExample
{
public static void Main()
{
var value = 20;
Console.WriteLine("In Main, value = {0}", value);
ModifyValue(ref value);
Console.WriteLine("Back in Main, value = {0}", value);
}
private static void ModifyValue(ref int i)
{
i = 30;
Console.WriteLine("In ModifyValue, parameter value = {0}", i);
return;
}
}
// The example displays the following output:
// In Main, value = 20
// In ModifyValue, parameter value = 30
// Back in Main, value = 30
by ref 매개 변수를 사용하는 일반적인 패턴은 변수 값의 교환을 포함합니다. 두 개의 변수를 참조로 메서드에 전달하고 메서드가 해당 내용을 바꿉니다. 다음 예제에서는 정수 값을 바꿉니다.
public static class RefSwapExample
{
static void Main()
{
int i = 2, j = 3;
Console.WriteLine("i = {0} j = {1}", i, j);
Swap(ref i, ref j);
Console.WriteLine("i = {0} j = {1}", i, j);
}
static void Swap(ref int x, ref int y) =>
(y, x) = (x, y);
}
// The example displays the following output:
// i = 2 j = 3
// i = 3 j = 2
참조 형식 매개 변수를 전달하면 해당 개별 요소 또는 필드의 값이 아니라 참조 자체의 값을 변경할 수 있습니다.
경우에 따라 메서드의 인수 개수를 정확하게 지정하라는 요구 사항은 제한적입니다.
params
키워드를 사용하여 매개 변수가 매개 변수 컬렉션임을 나타내면 가변 개수의 인수를 사용하여 메서드를 호출할 수 있습니다.
params
키워드로 태그가 지정된 매개 변수는 컬렉션 형식이어야 하며, 메서드의 매개 변수 목록에서 마지막 매개 변수여야 합니다.
그러면 호출자가 params
매개 변수에 대하여 다음 네 가지 방법 중 하나로 메서드를 호출할 수 있습니다.
- 원하는 개수의 요소를 포함하는 적절한 형식의 컬렉션 전달. 이 예제에서는 컴파일러가 적절한 컬렉션 형식을 만들도록 컬렉션 식을 사용합니다.
- 적절한 형식의 개별 인수가 포함된 쉼표로 구분된 목록을 메서드에 전달 컴파일러가 적절한 컬렉션 형식을 만듭니다.
-
null
을 전달 - 매개 변수 컬렉션에 인수를 제공 안 함.
다음 예제에서는 매개 변수 컬렉션의 모든 모음을 반환하는 GetVowels
메서드를 정의합니다.
Main
메서드는 해당 메서드를 호출하는 네 가지 방법을 모두 보여 줍니다. 호출자는 params
한정자를 포함하는 매개 변수에 대한 인수를 제공할 필요가 없습니다. 이 경우 매개 변수는 빈 컬렉션입니다.
static class ParamsExample
{
static void Main()
{
string fromArray = GetVowels(["apple", "banana", "pear"]);
Console.WriteLine($"Vowels from collection expression: '{fromArray}'");
string fromMultipleArguments = GetVowels("apple", "banana", "pear");
Console.WriteLine($"Vowels from multiple arguments: '{fromMultipleArguments}'");
string fromNull = GetVowels(null);
Console.WriteLine($"Vowels from null: '{fromNull}'");
string fromNoValue = GetVowels();
Console.WriteLine($"Vowels from no value: '{fromNoValue}'");
}
static string GetVowels(params IEnumerable<string>? input)
{
if (input == null || !input.Any())
{
return string.Empty;
}
char[] vowels = ['A', 'E', 'I', 'O', 'U'];
return string.Concat(
input.SelectMany(
word => word.Where(letter => vowels.Contains(char.ToUpper(letter)))));
}
}
// The example displays the following output:
// Vowels from array: 'aeaaaea'
// Vowels from multiple arguments: 'aeaaaea'
// Vowels from null: ''
// Vowels from no value: ''
C# 13 이전에서는 params
한정자를 단일 차원 배열에서만 사용할 수 있습니다.
메서드 정의는 해당 매개 변수가 필요하거나 선택 사항임을 지정할 수 있습니다. 기본적으로 매개 변수는 필수입니다. 선택적 매개 변수는 메서드 정의에 매개 변수의 기본값을 포함하여 지정됩니다. 메서드를 호출할 때 선택적 매개 변수에 대한 인수가 제공되지 않은 경우 기본값이 대신 사용됩니다.
다음 종류의 식 중 하나를 사용하여 매개 변수의 기본값을 할당합니다.
리터럴 문자열이나 숫자와 같은 상수
default(SomeType)
형식의 식입니다. 여기서SomeType
은 값 형식 또는 참조 형식일 수 있습니다. 참조 형식인 경우 사실상null
을 지정하는 것과 같습니다. 컴파일러가 매개 변수 선언에서 형식을 유추할 수 있으므로default
리터럴을 사용할 수 있습니다.new ValType()
형태의 식. 여기서ValType
은 값 형식입니다. 이 식은 형식의 실제 멤버가 아닌 값 형식의 암시적 매개 변수 없는 생성자를 호출합니다.참고
형태의 표현식이 값 형식의 명시적으로 정의된 매개변수가 없는 생성자를 호출할
new ValType()
경우, 기본 매개 변수 값은 컴파일 타임 상수여야 하므로 컴파일러가 오류를 발생시킵니다. 기본 매개 변수 값을 제공하려면default(ValType)
식 또는default
리터럴을 사용합니다. 매개 변수가 없는 생성자에 대한 자세한 내용은 구조체 형식 문서의 구조체 초기화 및 기본값 섹션을 참조하세요.
메서드에 필수 및 선택적 매개 변수가 둘 다 포함된 경우 선택적 매개 변수는 매개 변수 목록의 끝에서 모든 필수 매개 변수 다음에 정의됩니다.
다음 예제에서는 필수 매개 변수 하나와 선택적 매개 변수 두 개가 있는 ExampleMethod
메서드를 정의합니다.
public class Options
{
public void ExampleMethod(int required, int optionalInt = default,
string? description = default)
{
var msg = $"{description ?? "N/A"}: {required} + {optionalInt} = {required + optionalInt}";
Console.WriteLine(msg);
}
}
호출자는 인수가 제공되는 마지막 선택적 매개 변수까지 모든 선택적 매개 변수에 대한 인수를 제공해야 합니다. 예를 들어 ExampleMethod
메서드에서 호출자가 description
매개 변수에 대한 인수를 제공하는 경우 optionalInt
매개 변수에 대한 인수도 제공해야 합니다.
opt.ExampleMethod(2, 2, "Addition of 2 and 2");
는 유효한 메서드 호출이고, opt.ExampleMethod(2, , "Addition of 2 and 0");
은 "인수가 없습니다." 컴파일러 오류를 생성합니다.
명명된 인수 또는 위치 인수와 명명된 인수의 조합을 사용하여 메서드를 호출하는 경우 호출자는 메서드 호출에서 마지막 위치 인수 뒤에 오는 모든 인수를 생략할 수 있습니다.
다음 예제에서는 ExampleMethod
메서드를 세 번 호출합니다. 처음 두 메서드 호출은 위치 인수를 사용합니다. 첫 번째 호출은 선택적 인수를 둘 다 생략하고, 두 번째 호출은 마지막 인수를 생략합니다. 세 번째 메서드 호출은 필수 매개 변수에 대한 위치 인수를 제공하지만 description
인수를 생략하고 명명된 인수를 사용하여 optionalInt
매개 변수에 값을 제공합니다.
public static class OptionsExample
{
public static void Main()
{
var opt = new Options();
opt.ExampleMethod(10);
opt.ExampleMethod(10, 2);
opt.ExampleMethod(12, description: "Addition with zero:");
}
}
// The example displays the following output:
// N/A: 10 + 0 = 10
// N/A: 10 + 2 = 12
// Addition with zero:: 12 + 0 = 12
선택적 매개 변수를 사용하면 다음과 같이 오버로드 확인 또는 C# 컴파일러가 메서드 호출에 대해 호출할 오버로드를 결정하는 방식에 영향을 줍니다.
- 메서드, 인덱서 또는 생성자는 해당 매개 변수가 이름 또는 위치에 따라 단일 인수에 해당하고 이 인수를 매개 변수의 형식으로 변환할 수 있는 경우 실행 후보가 됩니다.
- 둘 이상의 인증서가 있으면 기본 설정 변환에 대한 오버로드 확인 규칙이 명시적으로 지정된 인수에 적용됩니다. 선택적 매개 변수에 대해 생략된 인수는 무시됩니다.
- 두 후보가 똑같이 정상이라고 판단되는 경우 기본적으로 호출에서 인수가 생략된 선택적 매개 변수가 없는 후보가 설정됩니다.
메서드는 호출자에 값을 반환할 수 있습니다. 반환 형식(메서드 이름 앞에 나열된 형식)이 void
(이)가 아니면 메서드는 return
키워드를 사용하여 값을 반환할 수 있습니다.
return
키워드와 그 뒤에 반환 형식과 일치하는 변수, 상수 또는 식이 따르는 문은 메서드 호출자에 해당 값을 반환합니다.
return
키워드를 사용하여 값을 반환하려면 void가 아닌 반환 값을 포함한 메서드가 필요합니다.
return
키워드는 메서드 실행을 중지합니다.
반환 형식이 void
이면 값이 없는 return
문을 사용하여 메서드 실행을 중지할 수 있습니다.
return
키워드가 없으면 메서드는 코드 블록 끝에 도달할 때 실행을 중지합니다.
예를 들어 이들 두 메서드에서는 return
키워드를 사용하여 정수를 반환합니다.
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2) =>
number1 + number2;
public int SquareANumber(int number) =>
number * number;
}
위의 예는 식 본문 멤버입니다. 식 본문 멤버는 식에서 반환된 값을 반환합니다.
본문과 return
문을 사용하여 메서드를 정의하도록 선택할 수도 있습니다.
class SimpleMathExtnsion
{
public int DivideTwoNumbers(int number1, int number2)
{
return number1 / number2;
}
}
메서드에서 반환된 값을 사용하려면 호출하는 메서드에서 같은 형식의 값으로 충분한 모든 경우에 메서드 호출 자체를 사용하면 됩니다. 반환 값을 변수에 할당할 수도 있습니다. 예를 들어, 다음 세 가지 코드 예는 동일한 목표를 달성합니다.
int result = obj.AddTwoNumbers(1, 2);
result = obj.SquareANumber(result);
// The result is 9.
Console.WriteLine(result);
result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));
// The result is 9.
Console.WriteLine(result);
result = obj2.DivideTwoNumbers(6,2);
// The result is 3.
Console.WriteLine(result);
메서드에서 둘 이상의 값을 반환하려는 경우도 있습니다.
튜플 형식과 튜플 리터럴을 사용하여 여러 값을 반환합니다. 튜플 형식은 튜플 요소의 데이터 형식을 정의합니다. 튜플 리터럴은 반환된 튜플의 실제 값을 제공합니다. 다음 예제에서 (string, string, string, int)
는 GetPersonalInfo
메서드에 의해 반환되는 튜플 형식을 정의합니다.
(per.FirstName, per.MiddleName, per.LastName, per.Age)
식은 튜플 리터럴입니다. 메서드는 PersonInfo
개체의 나이와 함께 이름, 중간 이름 및 성을 반환합니다.
public (string, string, string, int) GetPersonalInfo(string id)
{
PersonInfo per = PersonInfo.RetrieveInfoById(id);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
호출자는 다음 코드를 사용하여 반환된 튜플을 사용할 수 있습니다.
var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.Item1} {person.Item3}: age = {person.Item4}");
튜플 형식 정의의 튜플 요소에 이름을 할당할 수도 있습니다. 다음 예제에서는 명명된 요소를 사용하는 GetPersonalInfo
메서드의 대체 버전을 보여 줍니다.
public (string FName, string MName, string LName, int Age) GetPersonalInfo(string id)
{
PersonInfo per = PersonInfo.RetrieveInfoById(id);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
GetPersonalInfo
메서드에 대한 이전 호출을 다음과 같이 수정할 수 있습니다.
var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.FName} {person.LName}: age = {person.Age}");
메서드가 배열을 매개 변수로 사용하고 개별 요소의 값을 수정하는 경우 메서드가 배열을 반환할 필요가 없습니다. C#은 모든 참조 형식을 값으로 전달하고, 배열 참조의 값은 배열에 대한 포인터입니다. 다음 예제에서는 values
메서드에서 수행한 DoubleValues
배열 내용의 변경 사항을 배열에 대한 참조가 있는 모든 코드에서 관찰할 수 있습니다.
public static class ArrayValueExample
{
static void Main()
{
int[] values = [2, 4, 6, 8];
DoubleValues(values);
foreach (var value in values)
{
Console.Write("{0} ", value);
}
}
public static void DoubleValues(int[] arr)
{
for (var ctr = 0; ctr <= arr.GetUpperBound(0); ctr++)
{
arr[ctr] *= 2;
}
}
}
// The example displays the following output:
// 4 8 12 16
일반적으로 기존 형식에 메서드를 추가하는 방법에는 다음 두 가지가 있습니다.
- 해당 형식에 대한 소스 코드를 수정합니다. 원본을 수정하는 경우 메서드를 지원하기 위해 프라이빗 데이터 필드도 추가하면 호환성이 손상되는 변경이 발생합니다.
- 파생 클래스에서 새 메서드를 정의합니다. 구조체 및 열거형과 같은 다른 형식에 상속을 사용하여 이러한 방식으로 메서드를 추가할 수 없습니다. 봉인 클래스에 메서드를 "추가"하는 데 사용할 수도 없습니다.
확장 메서드를 사용하면 형식 자체를 수정하거나 상속된 형식에서 새 메서드를 구현하지 않고 기존 형식에 메서드를 "추가"할 수 있습니다. 또한 확장 메서드는 확장하는 형식과 동일한 어셈블리에 있을 필요가 없습니다. 형식의 정의된 멤버인 것처럼 확장 메서드를 호출합니다.
자세한 내용은 확장 메서드를 참조하세요.
비동기 기능을 사용하면 명시적 콜백을 사용하거나 수동으로 여러 메서드 또는 람다 식에 코드를 분할하지 않고도 비동기 메서드를 호출할 수 있습니다.
메서드에 async 한정자를 표시하면 메서드에서 await 연산자를 사용할 수 있습니다. 비동기 메서드에서 컨트롤이 await
식에 도달하면 대기 중인 작업이 완료되지 않은 경우 컨트롤이 호출자에게 반환되고 대기 중인 작업이 완료될 때까지 await
키워드가 있는 메서드의 진행이 일시 중단됩니다. 작업이 완료되면 메서드가 실행이 다시 시작될 수 있습니다.
참고
비동기 메서드는 아직 완료되지 않은 첫 번째 대기된 개체를 검색할 때나 비동기 메서드의 끝에 도달할 때 중에서 먼저 발생하는 시점에 호출자에게 반환됩니다.
비동기 메서드는 일반적으로 반환 형식이 Task<TResult>, Task, IAsyncEnumerable<T> 또는 void
입니다.
void
반환 형식은 기본적으로 void
반환 형식이 필요할 때 이벤트 처리기를 정의하는 데 사용됩니다.
void
를 반환하는 비동기 메서드는 대기할 수 없고 void를 반환하는 메서드의 호출자는 메서드가 throw하는 예외를 catch할 수 없습니다. 비동기 메서드에는 작업과 유사한 반환 형식이 있을 수 있습니다.
다음 예제에서 DelayAsync
는 정수를 반환하는 return 문을 포함하는 비동기 메서드입니다. 비동기 메서드이므로 메서드 선언에는 반환 형식의 Task<int>
(이)가 있어야 합니다. 반환 형식이 Task<int>
이므로 await
의 DoSomethingAsync
식 계산에서 다음 int result = await delayTask
문과 같이 정수가 생성됩니다.
class Program
{
static Task Main() => DoSomethingAsync();
static async Task DoSomethingAsync()
{
Task<int> delayTask = DelayAsync();
int result = await delayTask;
// The previous two statements may be combined into
// the following statement.
//int result = await DelayAsync();
Console.WriteLine($"Result: {result}");
}
static async Task<int> DelayAsync()
{
await Task.Delay(100);
return 5;
}
}
// Example output:
// Result: 5
비동기 메서드는 모든 in, ref 또는 out 매개 변수를 선언할 수 없지만, 이러한 매개 변수가 있는 메서드를 호출할 수는 있습니다.
비동기 메서드에 관한 자세한 내용은 async 및 await를 사용한 비동기 프로그래밍 및 비동기 반환 형식을 참조하세요.
식의 결과와 함께 즉시 반환하거나 메서드의 본문으로 단일 문을 포함하는 메서드 정의가 있는 것이 일반적입니다.
=>
(을)를 사용하여 이러한 메서드를 정의하기 위한 구문 바로 가기가 있습니다.
public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);
메서드가 void
를 반환하거나 비동기 메서드이면 메서드 본문은 문 식이어야 합니다(람다에서와 같음). 속성 및 인덱서의 경우 읽기 전용이어야 하며 get
접근자 키워드를 사용하지 않습니다.
반복기는 배열 목록과 같은 컬렉션에 대해 사용자 지정 반복을 수행합니다. 반복기는 yield return 문을 사용하여 각 요소를 따로따로 반환할 수 있습니다.
yield return
문에 도달하면 호출자가 시퀀스의 다음 요소를 요청할 수 있도록 현재 위치가 기억됩니다.
반복기의 반환 형식은 IEnumerable, IEnumerable<T>, IAsyncEnumerable<T>, IEnumerator 또는 IEnumerator<T>일 수 있습니다.
자세한 내용은 반복기를 참조하세요.
.NET 피드백
.NET은(는) 오픈 소스 프로젝트입니다. 다음 링크를 선택하여 피드백을 제공해 주세요.