// 기본 형식
(매개변수목록) => 식
// 1. 무명 함수 생성 by 람다식
delegate int Calculate(int a, int b); // 대리자 : 반환형식 + 매개변수 정의 -> 무명함수의 모습 결정
//...
static void Main(string[] args)
{
Calculate calc = (int a, int b) => a+b; // 무명함수 by 람다식
}
// 2. 형식 유추(Type Inference)를 통한 간결화
delegate int Calculate(int a, int b); // 대리자 : 반환형식 + 매개변수 정의
//...
static void Main(string[] args)
{
Calculate calc = (a, b) => a+b; // 형식 생략
// C# 컴파일러가 Calculator 대리자의 선언 코드로부터 익명 메소드의 매개변수 형식 유추
}
// 3. 무명 함수 생성 by 대리자
delegate int Calculate(int a, int b);
//...
static void Main(string[] args)
{
// 람다식과 달리 길게 표현
Calculate calc = delegate(int a, int b)
{
return a+b;
};
}
예제
using System;
namespace SimpleLambda
{
class MainApp
{
delegate int Calculate(int a, int b); // 대리자 : 반환형식 + 매개변수 정의
static void Main(string[] args)
{
Calculate calc = (a, b) => a + b; // 람다식 + 형식 유추(형식 생략)
Console.WriteLine($"{3} + {4} : {calc(3, 4)}");
}
}
}
// 기본 형식 : 화살표 오른쪽에 {코드 블록}
(매개변수_목록) => {
문장1;
문장2;
문장3;
...
}
// 반환 형식이 없는 무명 함수 생성 가능
delegate void DoSomething(); // 대리자
//...
static void Main(string[] args)
{
DoSomething DoIt = () => // 문 형식의 람다식 (반환값X)
{
Console.WriteLind("뭔가를");
Console.WriteLind("출력해보자.");
Console.WriteLind("이렇게!");
};
DoIt();
}
예제
using System;
namespace StatementLambda
{
class MainApp
{
delegate string Concatenate( string[] args ); // 대리자
static void Main(string[] args)
{
Concatenate concat = // 문 형식의 람다식
( arr ) =>
{
string result = "";
foreach (string s in arr)
result += s;
return result;
};
Console.WriteLine( concat(args) );
}
}
}
string[] args
- C# 프로그램 (exe 실행 파일)을 콘솔 윈도우(cmd.exe)에서 실행할 때 실행 코드 뒤에 작성한 옵션들(Command-Line Argument)은
args
에 전달된다.args
는 문자열 배열로 공백으로 구분된 옵션들이 차례대로 배열에 저장된다.
- Command-Line Argument : 고양이 우주 나비
=> args[0]=고양이, args[1]=우주, args[2]=나비- 만약 하나의 옵션 내 공백이 있을 경우
""
로 묶어 준다.
.NET
라이브러리에 미리 선언되어 있는 대리자Func 대리자
: 반환 값이 있는 익명 메소드/무명 함수용 대리자Action 대리자
: 반환 값이 없는 익명 메소드/무명 함수용 대리자예제
using System;
namespace FuncTest
{
class MainApp
{
static void Main(string[] args)
{
// Func<TResult> : 입력 매개변수 없는 버전
Func<int> func1 = () => 10; // 입력 매개변수는 없으며, 무조건 10 반환
Console.WriteLine($"func1() : {func1()}");
// Func<T1, TResult> : 매개변수 1개
Func<int, int> func2 = (x) => x * 2; // 입력 매개변수는 int 형식 하나, 반환 형식도 int
Console.WriteLine($"func2(4) : {func2(4)}");
// Func<T1, T2, TResult> : 매개변수 2개
Func<double, double, double> func3 = (x, y) => x / y; // 입력 매개변수는 double 형식 둘, 반환 형식도 double
Console.WriteLine($"func3(22, 7) : {func3(22, 7)}");
}
}
}
예제
using System;
namespace ActionTest
{
class MainApp
{
static void Main(string[] args)
{
// Action<T> : 매개변수 1개 버전
Action act1 = () => Console.WriteLine("Action()");
act1();
int result = 0;
Action<int> act2 = (x) => result = x * x; // result에 x * x 결과 저장
act2(3);
Console.WriteLine($"result : {result}");
// Action<T1, T2> : 매개변수 2개 버전
Action<double, double> act3 = (x, y) =>
{
double pi = x / y;
Console.WriteLine($"Action<T1, T2>({x}, {y}) : {pi}");
};
act3(22.0, 7.0);
}
}
}
식을 트리로 표현한 자료 구조
Expression<TDelegate>
클래스 이용)노드(Node, 마디)로 구성
컴파일러나 인터프리터 제작에 응용
Expression 클래스 (System.Linq.Expression
)
팩토리 메소드(Factory Method)
- 클래스의 인스턴스 생성을 담당하는 메소드
- 객체 생성 과정을 별도의 메소드에 구현해놓으면 코드의 복잡도를 상당히 줄일 수 있다.
- Expression 클래스의 정적 팩토리 메소드들은 파생 클래스들의 인스턴스를 생성하는 기능을 제공함으로써 편리성 제공
※ Expression을 상속하므로// Expression 클래스의 팩토리 메소드를 통해 객체 생성 Expression const1 = Expression.Constant(1); // 상수 1 표현 객체 Expression param1 = Expression.Parameter(typeof(int), "x"); // 매개변수 x 표현 객체 Expression exp = Expression.Add(const1, param1); // 덧셈 연산 수행 객체
ConstantExpression
이 아닌
Expression
형식으로 선언하여도 참조를 통해 가리킬 수 있다.
코드를 데이터로써 보관
예제
// 1. 식 트리 by Expression<TDelegate> //
using System;
using System.Linq.Expressions; // Expression 클래스
namespace UsingExpressionTree
{
class MainApp
{
static void Main(string[] args)
{
// 1*2+(x-y) 구현 //
Expression const1 = Expression.Constant(1); // 상수 1
Expression const2 = Expression.Constant(2); // 상수 2
Expression leftExp = Expression.Multiply(const1, const2); // 곱 연산 : 1 * 2
Expression param1 =
Expression.Parameter(typeof(int)); // x를 위한 변수
Expression param2 =
Expression.Parameter(typeof(int)); // y를 위한 변수
Expression rightExp = Expression.Subtract(param1, param2); // 빼기 연산 : x - y
Expression exp = Expression.Add(leftExp, rightExp); // 곱 연산 + 빼기 연산
// Expression <TDelegate>로 식 트리 생성
Expression<Func<int, int, int>> expression =
Expression<Func<int, int, int>>.Lambda<Func<int, int, int>>(
exp, new ParameterExpression[]{
(ParameterExpression)param1,
(ParameterExpression)param2});
Func<int, int, int> func = expression.Compile(); // 실행가능한 코드로 컴파일
// x = 7, y = 8
Console.WriteLine($"1*2+({7}-{8}) = {func(7,8)}"); // 컴파일한 무명 함수 실행
}
}
}
// 2. 식 트리 by 람다식 //
// 이 경우 Expression 형식은 불변이므로 "동적으로" 식 트리를 만들기 어렵지만
// 더 간편하게 만들 수 있다.
using System;
using System.Linq.Expressions;
namespace ExpressionTreeViaLambda
{
class MainApp
{
static void Main(string[] args)
{
Expression<Func<int, int, int>> expression =
(a, b) => 1*2+(a-b);
Func<int, int, int> func = expression.Compile();
// x = 7, y = 8
Console.WriteLine($"1*2+({7}-{8}) = {func(7,8)}"); // 컴파일한 무명 함수 실행
}
}
}
멤버 => 식;
예제
using System;
using System.Collections.Generic;
namespace ExpressionBodiedMember
{
class FriendList // Friend 클래스 선언
{
private List<string> list = new List<string>(); // 이름 넣을 리스트 선언
public void Add(string name) => list.Add(name); // 이름 추가
public void Remove(string name) => list.Remove(name); // 이름 삭제
public void PrintAll() // 리스트에 있는 모든 이름 출력
{
foreach (var s in list)
Console.WriteLine(s);
}
public FriendList() => Console.WriteLine("FriendList()"); // 생성자
~FriendList() => Console.WriteLine("~FriendList()"); // 종료자
// public int Capacity => list.Capacity; // 읽기 전용 속성
public int Capacity // 읽기/쓰기 모두 가능한 속성
{
get => list.Capacity;
set => list.Capacity = value;
}
// public string this[int index] => list[index]; // 읽기 전용 인덱서
public string this[int index] // 읽기/쓰기 모두 가능한 인덱서
{
get => list[index];
set => list[index] = value;
}
}
class MainApp
{
static void Main(string[] args)
{
FriendList obj = new FriendList();
obj.Add("Eeny");
obj.Add("Meeny");
obj.Add("Miny");
obj.Remove("Eeny");
obj.PrintAll();
Console.WriteLine($"{obj.Capacity}");
obj.Capacity = 10;
Console.WriteLine($"{obj.Capacity}");
Console.WriteLine($"{obj[0]}");
obj[0] = "Moe";
obj.PrintAll();
}
}
}
Func<int> func_1 = () => 10;
Func<int, int> func_2 = (a) => a*2;
Console. WriteLine(func_1() + func_2(30)); // 10 + 30*2 = 70
// 기본 코드
using System;
namespace _14_2
{
class MainApp
{
static void Main(string[] args)
{
int[] array = { 11, 22, 33, 44, 55 };
foreach (int a in array)
{
Action action = new Action
(
delegate()
{
Console.WriteLine(a*a);
}
);
}
}
}
}
// 람다식으로 수정
using System;
namespace _14_2
{
class MainApp
{
static void Main(string[] args)
{
int[] array = { 11, 22, 33, 44, 55 };
foreach (int a in array)
{
int result = 0;
Action<int> act1 = (a) => result = a * a;
act1(a);
Console.WriteLine($"a = {a} => result = {result}");
}
}
}
}