성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - CachedAnonymousMethodDelegate 유형의 코드 생성</h1> <p> C# 문법이 발전하면서 컴파일러가 자동 생성해 주는 코드가 많아졌습니다. 그런데, 가만 보면 이런 것에도 패턴이 있는 것 같습니다. 가령, CachedAnonymousMethodDelegate라는 유형이 있는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > SynthesizedLocalKind ; http://source.roslyn.io/#Microsoft.CodeAnalysis/SynthesizedLocalKind.cs,c465228f29a95c51,references /// <summary> /// Local variable used to cache a delegate that is used in inner block (possibly a loop), /// and can be reused for all iterations of the loop. /// </summary> CachedAnonymousMethodDelegate = 31, </pre> <br /> CachedAnonymousMethodDelegate 유형의 로컬 변수를 생성하려면 다음과 같이 예제 구성을 하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Collections.Generic; using System.Linq; namespace ConsoleApp1 { class Program { static void Main(string[] args) { DoMethod(); } private static void DoMethod() { <span style='color: blue; font-weight: bold'>Func<string, bool> func3 = (arg) => { return true; };</span> List<string> list = new List<string>(); var list2 = list.Where(<span style='color: blue; font-weight: bold'>func3</span>); } } } </pre> <br /> Visual Studio 2013에서 위의 소스 코드를 컴파일하고 .NET Reflector에서 "C# - None" 옵션으로 보면 다음과 같이 DoMethod 내부에 코딩한 람다 함수가 "CS$<>9__<span style='color: blue; font-weight: bold'>CachedAnonymousMethodDelegate</span>1" 이름의 멤버 필드로 Program 클래스에 정의되면서 캐시 역할의 변수를 합니다. 또한 람다 함수의 코드는 "<DoMethod>b__0"라는 멤버 메서드로 자동 생성되고! <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > internal class Program { // Fields <span style='color: blue; font-weight: bold'>[CompilerGenerated] private static Func<string, bool> CS$<>9__CachedAnonymousMethodDelegate1;</span> // Methods public Program() { base..ctor(); return; } <span style='color: blue; font-weight: bold'>[CompilerGenerated] private static bool <DoMethod>b__0(string arg) { bool flag; flag = 1; Label_0005: return flag; }</span> private static void DoMethod() { Func<string, bool> func; List<string> list; IEnumerable<string> enumerable; <span style='color: blue; font-weight: bold'>if (CS$<>9__CachedAnonymousMethodDelegate1 != null) { goto Label_001B; } CS$<>9__CachedAnonymousMethodDelegate1 = new Func<string, bool>(null, <DoMethod>b__0);</span> Label_001B: func = CS$<>9__CachedAnonymousMethodDelegate1; list = new List<string>(); enumerable = Enumerable.Where<string>(list, func); return; } private static void Main(string[] args) { DoMethod(); return; } } </pre> <br /> 재미있는 것은, cache 변수의 역할을 하는 멤버 필드의 이름에 SynthesizedLocalKind::CachedAnonymousMethodDelegate 상숫값의 이름이 반영되어 있다는 것입니다. 게다가 CS$...에 붙는 번호들 같은 경우에도 그냥 붙는 것이 아니라고 합니다. 이에 대해서는 아래의 글을 (재미 삼아) 보시면 될 것 같습니다. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Where to learn about VS debugger 'magic names' ; <a target='tab' href='http://stackoverflow.com/questions/2508828/where-to-learn-about-vs-debugger-magic-names'>http://stackoverflow.com/questions/2508828/where-to-learn-about-vs-debugger-magic-names</a> </pre> <br /> 그런데 역시나 이런 내부적인 규칙들은 public이 아니라는 점에 주의해야 합니다. 실제로 Visual Studio 2015에서 위의 소스 코드를 빌드하면 다음과 같이 전혀 다른 결과를 얻게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > internal class Program { // Methods public Program() { base..ctor(); return; } private static void DoMethod() { Func<string, bool> func; List<string> list; IEnumerable<string> enumerable; Label_0020: <span style='color: blue; font-weight: bold'>func = <>c.<>9__1_0 ?? (<>c.<>9__1_0 = new Func<string, bool>(<>c.<>9, this.<DoMethod>b__1_0));</span> list = new List<string>(); enumerable = Enumerable.Where<string>(list, func); return; } private static void Main(string[] args) { DoMethod(); return; } <span style='color: blue; font-weight: bold'>[Serializable, CompilerGenerated] private sealed class <>c { // Fields public static readonly Program.<>c <>9; public static Func<string, bool> <>9__1_0; // Methods static <>c() { <>9 = new Program.<>c(); return; } public <>c() { base..ctor(); return; } internal bool <DoMethod>b__1_0(string arg) { bool flag; flag = 1; Label_0005: return flag; } }</span> } </pre> <br /> 즉, CachedAnonymousMethodDelegate 접미사가 붙은 멤버 필드 대신 별도의 임시 클래스(<>c)가 만들어지고 그 안에 필드와 메서드의 본체가 정의됩니다.<br /> <br /> 이런 차이가 있기 때문에 람다 함수 안에서 다음과 같은 타입 의존적인 코드를 하게 되면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > class Program { static void Main(string[] args) { Program pg = new Program(); pg.DoMethod(); } private void DoMethod() { Func<string, bool> func3 = (arg) => { <span style='color: blue; font-weight: bold'>StackFrame st = new StackFrame(); Console.WriteLine(st.GetMethod().DeclaringType.Name); Console.WriteLine(st.GetMethod().DeclaringType.FullName);</span> return true; }; List<string> list = new List<string>(); list.Add("TEST"); var list2 = list.Where(func3); list2.ToList(); } } </pre> <br /> Visual Studio 2013에서는 다음과 같이 출력이 되고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Type.Name: Program Type.FullName: ConsoleApp1.Program </pre> <br /> Visual Studio 2015 이후로는 이런 결과가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Type.Name: <>c Type.FullName: ConsoleApp1.Program+<>c </pre> <br /> 재미있는 것은, Visual Studio 2013에서도 람다 함수 내에 변수를 capture 하게 되면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public string DoMethod() { <span style='color: blue; font-weight: bold'>StringBuilder sb = new StringBuilder();</span> Func<string, bool> func3 = (arg) => { <span style='color: blue; font-weight: bold'>sb.AppendLine(arg);</span> return true; }; List<string> list = new List<string>(); list.Add("TEST"); var list2 = list.Where(func3); list2.ToList(); } </pre> <br /> 2015에서와 같은 결과가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Visual Studio 2013 Type.Name: <>c Type.FullName: ConsoleApp1.Program+<>c </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1710
(왼쪽의 숫자를 입력해야 합니다.)