Microsoft MVP성태의 닷넷 이야기
.NET Framework: 744. C# 6 - Expression bodied function [링크 복사], [링크+제목 복사]
조회: 2620
글쓴 사람
홈페이지
첨부 파일
 

C# 6 - Expression bodied function

아래와 같은 글이 있군요. ^^

식 본문 함수의 최적화
왜 우리는 람다를 더 써야 하는가
; https://phillyai.github.io/2018-05-08-Expression-Bodied-Function/

위의 글에서는 다음의 2가지 메서드를,

int Add(int a, int b) { return a + b; }
int AddLambda(int a, int b) => a + b;

빌드했을 때, 람다 형식으로 작성한 경우 컴파일러가 더 최적화를 잘 해주기 때문이라고 합니다. 실제로 IL 코드로 보면 다음과 같이 차이가 납니다.

.method private hidebysig instance int32 Add(int32 a, int32 b) cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 num)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: ldarg.2 
    L_0003: add 
    L_0004: stloc.0 
    L_0005: br.s L_0007
    L_0007: ldloc.0 
    L_0008: ret 
}

.method private hidebysig instance int32 AddLambda(int32 a, int32 b) cil managed
{
    .maxstack 8
    L_0000: ldarg.1 
    L_0001: ldarg.2 
    L_0002: add 
    L_0003: ret 
}

보다시피 람다로 했을 때 코드가 더 간결합니다. 좀 더 기술적인 용어로 첫 번째 Add 메서드는 Fat method 형식이고, 두 번째 Lambda 메서드는 Thin method 형식입니다. 그런데, 사실 이건 Debug 모드로 빌드했기 때문에 나온 결과일 뿐입니다. Release 모드로 빌드하면 다음과 같이 2개 모두 동일한 IL 코드를 볼 수 있습니다.

.method private hidebysig instance int32 Add(int32 a, int32 b) cil managed
{
    .maxstack 8
    L_0000: ldarg.1 
    L_0001: ldarg.2 
    L_0002: add 
    L_0003: ret 
}

.method private hidebysig instance int32 AddLambda(int32 a, int32 b) cil managed
{
    .maxstack 8
    L_0000: ldarg.1 
    L_0001: ldarg.2 
    L_0002: add 
    L_0003: ret 
}

그러니까... 사실 저런 이유로 굳이 람다를 더 쓸 필요는 없습니다.

참고로, 디버그 모드에서 람다 메서드가 더 최적화가 잘 되는 것은, 람다 메서드의 경우 tiny header를 가질 수 있는 요건을 쉽게 충족하기 때문입니다.




"왜 우리는 람다를 더 써야 하는가" 글에서 한 가지 더 이상한 점이 있는데요. 해당 최적화가 Expression에서만 적용되고 Statement에 대해 적용되지 않는다면서 쓴 코드가 바람직하지 않습니다.

void DoLambda() => Do();

위에서 DoLambda의 body 역시 (Statement가 아닌) Expression으로 작성된 것입니다. 저 구문의 영문 이름이 "Expression bodied function"인데요, 즉 저 구문에서는 반드시 Expression만 허용됩니다. 만약 저 코드를 Statement로 만들려면 다음과 같이 코딩해야 하는데,

void DoLambda() => { Do(); } // 컴파일 오류 - Error CS1525 Invalid expression term '{'

그럼 CS1525 컴파일 오류가 발생합니다. 왜냐하면 Expression에서는 블록이 허용되지 않기 때문입니다. (블록은 Statement에만 허용됩니다.)

사실 정확히 말하면 아래의 코드는,

int AddLambda(int a, int b) => a + b;

말 그대로 "Expression bodied function"입니다. 비록 C#의 람다 표현으로 작성하긴 했지만 expression만 허용되는 람다입니다. 반면, 람다 식이 아닌 람다 문을 활용하면 다음과 같이 쓸 수 있습니다.

static void Main(string[] args)
{
    Action action = () => // Statement를 가진 람다 메서드
    {
        Console.WriteLine();
    };
}

그러니까, "왜 우리는 람다를 더 써야 하는가" 글의 제목도 좀 맞지 않습니다. 실제로 저 글의 내용이 맞다고 가정했을 때 좀 더 정확히는 "왜 우리는 Expression bodied function을 사용해야 하는가"라고 해야 합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]





[최초 등록일: ]
[최종 수정일: 6/8/2018 ]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer@outlook.com

비밀번호

댓글 쓴 사람
 




1  2  3  4  5  6  7  8  9  10  11  12  13  14  [15]  ...
NoWriterDateCnt.TitleFile(s)
11911정성태5/23/20191375VS.NET IDE: 136. Visual Studio 2019 - 리눅스 C/C++ 프로젝트에 인텔리센스가 동작하지 않는 경우
11910정성태5/24/20192607Math: 50. C# - MathNet.Numerics의 Matrix(행렬) 연산파일 다운로드1
11909정성태5/25/20191826.NET Framework: 837. C# - PLplot 사용 예제 [1]파일 다운로드1
11908정성태5/22/20191202.NET Framework: 836. C# - Python range 함수 구현파일 다운로드1
11907정성태6/4/2019989오류 유형: 541. msbuild - MSB4024 The imported project file "...targets" could not be loaded
11906정성태5/21/2019843.NET Framework: 835. .NET Core/C# - 리눅스 syslog에 로그 남기는 방법
11905정성태5/21/20191208.NET Framework: 834. C# - 폴더 경로 문자열에서 "..", "." 표기를 고려한 최종 문자열을 얻는 방법 - 두 번째 이야기
11904정성태5/21/20192403.NET Framework: 833. C# - Open Hardware Monitor를 이용한 CPU 온도 정보파일 다운로드1
11903정성태5/21/20191326오류 유형: 540. .NET Core - System.PlatformNotSupportedException: The named version of this synchronization primitive is not supported on this platform.
11902정성태5/21/2019919오류 유형: 539. mstest 실행 시 "The directory name is invalid." 오류 발생
11901정성태5/21/20191528오류 유형: 538. msbuild 오류 - Could not find a part of the path '%LOCALAPPDATA%\Temp\2\.NETFramework,Version=v4.0.AssemblyAttributes.cs'
11900정성태3/12/20201461오류 유형: 537. "sfc /scannow" 실행 중 시스템이 부팅되는 현상
11899정성태5/17/20191535Linux: 9. Linux에서 윈도우의 OutputDebugString 대신 사용할 수 있는 syslog [1]
11898정성태5/20/20191596VC++: 130. C++ string의 c_str과 data 함수의 차이점 [3]
11897정성태5/16/20192856오류 유형: 536. Visual Studio - "Developer Pack"을 설치했는데도 "대상 프레임워크" 목록에 나오지 않는 경우 [1]
11896정성태5/15/20192237개발 환경 구성: 440. C#, C++ - double의 Infinity, NaN 표현 방식파일 다운로드1
11895정성태5/12/20191558.NET Framework: 832. ML.NET Model Builder - 회귀(Regression), 다중 분류(Multi-class classification) 예제파일 다운로드1
11894정성태5/12/20192071VS.NET IDE: 135. Visual Studio - ML.NET Model Builder 소개 [1]
11893정성태5/10/20191640오류 유형: 535. C# 6.0 이상의 문법을 컴파일 시 오류가 발생한다면?
11892정성태5/10/20191096웹: 38. HTTP Cookie의 expires 시간 형식(RFC7231)
11891정성태5/9/20191387.NET Framework: 831. (번역글) .NET Internals Cookbook Part 12 - Memory structure, attributes, handles
11890정성태5/8/20191116개발 환경 구성: 439. "Visual Studio Enterprise is required to execute the test." 메시지와 관련된 코드 기록
11889정성태5/8/20191246개발 환경 구성: 438. mstest, QTAgent의 로그 파일 설정 방법
11888정성태5/8/20192343.NET Framework: 830. C# - 비동기 호출을 취소하는 CancellationToken의 간단한 예제 코드파일 다운로드1
11887정성태5/8/20191550.NET Framework: 829. C# - yield 문을 사용할 수 있는 메서드의 조건
11886정성태5/8/20191577오류 유형: 534. mstest.exe 실행 시 "Visual Studio Enterprise is required to execute the test." 오류 [2]
1  2  3  4  5  6  7  8  9  10  11  12  13  14  [15]  ...