5. C#과 닷넷 프레임워크 – CIL (3)
닷넷 언어를 만드는 2가지 방법
1. 소스코드 CLI 표준에 정의된 바이너리를 직접 생성
2. 소스코드 IL 언어 ilasm.exe를 이용해서 CLI 표준에 정의된 바이너리를 생성
6. C#과 닷넷 프레임워크 – CIL (4)
IL에서만 가능한 표현
표현
IL
C#
VB.NET
리턴 값에 따른 메서드 오버로드
O
X
X
[protected and internal] 접근자
O
X
X
struct에서 인자 없는 생성자 정의
O
X
X
7. C#과 닷넷 프레임워크 – 컴파일 (1)
두 번의 컴파일
C# 소스코드 중간 언어(Intermediate Language) 기계어
C# 컴파일러
디버그
JIT 컴파일러
릴리즈
디버그
릴리즈
8. C#과 닷넷 프레임워크 – 컴파일 (2)
언어 컴파일러
생산된 IL만 올바르다면 언어의 문법은 자유롭게 확장 가능
ex) VB.NET 의 Module에 정의되는 전역 변수
JIT 컴파일러
실행 시 IL 코드를 Debug / Release 모드에 따라 기계어로 변환
ex) Field로 정의하면 Property get/set으로 정의하는 것보다 빠른가?
ex) 무한 재귀호출이 항상 StackOverflowException을 발생할까?
9. C#과 닷넷 프레임워크 – 버전
C#과 닷넷 프레임워크 버전 관계
닷넷 버전
C# 버전
주요 특징
1.0 ~ 1.1
1.0
C# 1.0
2.0
2.0
Generics
3.0 ~ 3.5
3.0
LINQ
4.0
4.0
dynamic 예약어
4.5
5.0
async/await 예약어
10. C# 언어의 발전 요소
• CLR – 2.0(4.0) 신규 IL
• BCL (Base Class Library)
• 언어 표현
- Syntactic Sugar (단축 표기)
- 기존의 IL 표현력 추가
IL
BCL
언어 표현
-
-
-
14. C# 2.0 - ?? 연산자
string txt = null;
if (txt == null)
{
Console.WriteLine("(null)");
}
else
{
Console.WriteLine(txt);
}
string txt = null;
Console.WriteLine(txt ?? "(null)");
IL
BCL
언어 표현
-
-
O
15. C# 2.0 – yield return/break (1)
• IEnumerable의 단축 표기
F#
C#
list
IList, ICollection
sequence
IEnumerable
주요 특징
요소의 전체 목록을 보유
필요한 순간에 요소의 값을 계산
IL
BCL
언어 표현
-
-
O
16. C# 2.0 – yield return/break (2)
• IList / ICollection
public class ListNatural
{
ArrayList GetNumbers(int max)
{
ArrayList list = new ArrayList();
for (int i = 1; i <= max; i++)
{
list.Add(i);
}
return list;
}
}
17. C# 2.0 – yield return/break (3)
• IEnumerable
public class SequenceNatural : IEnumerable, IEnumerator
{
int _current;
public IEnumerator GetEnumerator()
{
_current = 0;
return this;
foreach
}
(var item in new YieldNatural().GetNumbers())
{
Console.WriteLine(item);
if ((int)item == 10)
{
break;
}
public object Current
{
get { return _current; }
}
public bool MoveNext()
{
_current++;
return true;
}
public void Reset()
{
_current = 0;
}
}
}
18. C# 2.0 – yield return/break (3)
• yield return/break
public class YieldNatural
{
public IEnumerable GetNumbers()
{
int n = 1;
while (true)
{
yield return n;
// if (n == 100) yield break;
n++;
}
}
}
19. C# 2.0 – partial type (1)
• 클래스의 구현을 2개 이상으로 분리
partial class MyClass
{
public void Do()
{
Console.Write(_number);
}
}
partial class MyClass
{
private int _number = 1;
}
partial class MyClass
{
public void Do()
{
Console.Write(_number);
}
private int _number = 1;
}
IL
BCL
언어 표현
-
-
O
20. C# 2.0 – partial type (2)
• 자동 코드 생성의 문제점 해결!
-
Visual Studio 2002/2003 2005
• F#은 WPF를 왜 지원하지 않는가?
21. C# 2.0 – 익명 메서드 (1)
•
이름 없는 메서드 정의 가능
static void Main(string[] args)
{
Thread t = new Thread(func);
t.Start();
}
private static void func(object obj)
{
Console.Write("...");
}
static void Main(string[] args)
{
Thread t = new Thread(
delegate (object obj)
{
Console.Write("...");
}
);
t.Start();
}
IL
BCL
언어 표현
-
-
O
22. C# 2.0 – 익명 메서드 (2)
delegate 타입의 인자로 인라인 메서드 정의
•
using System;
namespace ConsoleApplication1
{
class Program
{
delegate void Functor(object obj);
static void Main(string[] args)
{
Functor logOutput = delegate(object obj) { Console.Write(obj); };
logOutput("test");
}
}
}
23. C# 2.0 – 익명 메서드 (3)
•
이벤트 처리기
this.textBox1.TextChanged += delegate (object sender, EventArgs e)
{
Console.WriteLine(“Do!”);
};
// 또는 delegate의 인자를 사용하지 않는다면 생략 가능
this.textBox1.TextChanged += delegate { Console.WriteLine(“Do!”); };
24. C# 2.0 – static class
•
•
IL 코드 표현: 상속 불가능한 추상 클래스
C# 컴파일러: 인스턴스 멤버 정의 불가능
abstract class AbstractClass
{
}
static class StaticClass
{
}
.class private abstract auto ansi beforefieldinit AbstractClass
extends [mscorlib]System.Object
{
.method family hidebysig specialname rtspecialname instance
void .ctor() cil managed
{
}
}
.class private abstract auto ansi sealed beforefieldinit
StaticClass
extends [mscorlib]System.Object
{
}
IL
BCL
언어 표현
-
-
O
25. C# 2.0 – 제네릭 (1)
•
C++의 template과 유사
public class NewStack<T>
{
T [] _objList;
int _pos;
public NewStack(int size)
{
_objList = new T[size];
}
public void Push(T newValue)
{
_objList[_pos] = newValue;
_pos++;
}
public T Pop()
{
_pos--;
return _objList[_pos];
}
}
IL
BCL
언어 표현
O
-
-
26. C# 2.0 – 제네릭 (2)
•
메서드 수준의 제네릭도 지원
public class LogOutput
{
public void Output<T,V>(T value1, V value2)
{
Console.WriteLine(value1 + “: ” + value2);
}
}
27. C# 2.0 – 제네릭 (3)
•
박싱/언박싱 문제를 해결
ArrayList list = new ArrayList();
list.Add(5); // void Add(object value)
list.Add(6);
List<int> list = new List<int>();
list.Add(5);
//
void Add(T item)
list.Add(6);
// void Add(int item);
28. C# 2.0 – 제네릭 (4)
제약 1 – 상속 타입
•
public static T Max<T>(T item1, T item2) where T : IComparable
{
if (item1.CompareTo(item2) >= 0)
{
return item1;
}
return item2;
}
29. C# 2.0 – 제네릭 (5)
제약 2 – 값/참조 타입
•
public static void Print<T,V>(T item1, V item2) where T : struct
where V : class
{
Console.WriteLine(item1);
if (item2 != null) // 값 형식인 item1과 비교한다면 컴파일 에러
{
Console.WriteLine(item2);
}
}
30. C# 2.0 – 제네릭 (6)
제약 3 – 인자 없는 생성자 필수
•
public static T AllocateIfNull<T>(T item) where T : class, new()
{
if (item == null)
{
item = new T();
}
return item;
}
31. C# 2.0 – 제네릭 (7)
•
기존 컬렉션의 제네릭 버전 제공
.NET 1.x 컬렉션
대응되는 제네릭 버전의 컬렉션
ArrayList
List<T>
Hashtable
Dictionary<TKey, TValue>
SortedList
SortedDictionary<TKey, TValue>
Stack
Stack<T>
Queue
Queue<T>
32. C# 2.0 – Nullable 타입
•
•
.NET 2.0 BCL: Nullable<T> 구조체 추가
C#의 경우 T? 형태로 단축 표기
int? value1 = null;
short? value2 = 5;
// Nullable<int> value1;
// Nullable<short> value2;
if (value1.HasValue)
{
Console.WriteLine(value1);
}
Console.WriteLine(value2); // Console.WriteLine(value2.Value);
IL
BCL
언어 표현
-
O
O
34. C# 3.0
• 자동 구현 속성
• 컬렉션 초기화
• LINQ
var
객체 초기화
익명 타입
확장 메서드
람다 식
35. C# 3.0 – 자동 구현 속성 (1)
Field + Property 구현을 단순화
•
class Person
{
string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
public string Name { get; set; }
public int Age { get; set; }
}
IL
BCL
언어 표현
-
-
O
36. C# 3.0 – 자동 구현 속성 (2)
•
get/set의 접근 제한자
class Person
{
public string Name
{
get;
protected set;
}
public int Age
{
get;
private set;
}
}
37. C# 3.0 – 컬렉션 초기화
•
•
ICollection 인터페이스를 구현한 타입
컬렉션의 요소를 new 구문에서 추가
List<int> numbers = new List<int>();
numbers.Add(0);
numbers.Add(1);
numbers.Add(2);
numbers.Add(3);
numbers.Add(4);
List<int> numbers = new List<int> { 0, 1, 2, 3, 4 };
IL
BCL
언어 표현
-
-
O
38. C# 3.0 – LINQ
•
발음: LINK? LIN-Q?
둘 다 옳다.
“Moq”도 “mock”으로 발음하기도 하지만 “mock u”로
발음하는 것처럼,
일반적으로 “link”라고 발음하지만 “link u”로 발음하기도 함.
주의 사항: FAQ에 대해서까지 이 규칙을 적용해서는 안됨
(출처: http://stackoverflow.com/questions/2659330/how-to-pronounce-linq)
39. C# 3.0 – LINQ (1)
•
LINQ: Language-INtegrated Query
언어에 통합된 쿼리 표현식(Query Expressions)
List<Person> people = new List<Person>
{
new Person { Name = "Anders", Age = 47, Married = true },
new Person { Name = "Hans", Age = 25, Married = false },
};
IEnumerable<Person> all = from person in people
select person;
foreach (Person item in all)
{
Console.WriteLine(item);
}
IL
BCL
언어 표현
-
O
O
40. C# 3.0 – LINQ (2)
•
SQL 쿼리의 SELECT와 유사
방식
코드
SQL
SELECT * FROM people
LINQ
IEnumerable<Person> all = from person in people
select person;
메서드
IEnumerable<Person> SelectFunc(List<Person> people)
{
foreach (Person item in people)
{
yield return item;
}
}
41. C# 3.0 – var 예약어
•
•
컴파일러가 로컬 변수의 형식을 추론
C++ 11의 auto 예약어와 동격
IEnumerable<Person> all = from person in people
select person;
var all = from person in people
select person;
foreach (var item in all)
{
Console.WriteLine(item);
}
IL
BCL
언어 표현
-
-
O
42. C# 3.0 – 객체 초기화 (1)
•
공용 속성을 통해 객체 생성 시에 초기화
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Person p1 = new Person();
p1.Name = “Hans”;
p1.Age = 30;
Person p2 = new Person { Name = "Tom", Age = 29 };
IL
BCL
언어 표현
-
-
O
43. C# 3.0 – 객체 초기화 (2)
•
SELECT * FROM people
SELECT Name, Age FROM people
SELECT Name, Married FROM people
var all = from person in people
select person;
var all = from person in people
select new Person { Name = person.Name, Age = person.Age };
var all = from person in people
select new Person { Name = person.Name,
Married = person.Married };
44. C# 3.0 – 객체 초기화 (4)
•
컬렉션 초기화 + 객체 초기화
List<Person> list = new List<Person>
{
new Person { Name = "Ally", Age = 35 },
new Person { Name = "Luis", Age = 40 },
};
45. C# 3.0 – 익명 타입 (1)
•
이름 없는 타입
내부적인 처리는 익명 메서드와 유사
•
var 사용은 필수
var p = new { Count = 10, Title = "Anders" };
Console.WriteLine(p.Title + ": " + p.Count);
IL
BCL
언어 표현
-
-
O
46. C# 3.0 – 익명 타입 (2)
•
LINQ - SELECT
var all = from person in people
select new { Name = person.Name, Age = person.Age };
var all = from person in people
select new { Name = person.Name,
Married = person.Married };
foreach (var item in all)
{
Console.WriteLine(item);
}
47. C# 3.0 – 익명 타입 (3)
•
SELECT p.Name, p.Age, lang.Language
FROM people as p
INNER JOIN Language as lang
ON p.Name = lang.Name
var all = from p
in people
join lang in languages on p.Name equals lang.Name
select new { Name = p.Name,
Age = p.Age,
Language = lang.Language };
foreach (var item in all)
{
Console.WriteLine(item);
}
48. C# 3.0 – 확장 메서드 (1)
정적 메서드를 마치 인스턴스 메서드처럼 사용
•
class Program
{
static void Main(string[] args)
{
string txt = "http://www.naver.com";
string contents = txt.TextFromUrl();
Console.WriteLine(contents);
}
}
static class StringExtension
{
public static string TextFromUrl(this string txt)
{
WebClient wc = new WebClient();
return wc.DownloadString(txt);
IL
}
}
-
BCL
언어 표현
-
O
49. C# 3.0 – 확장 메서드 (2)
결국 정적 메서드 호출
•
class Program
{
static void Main(string[] args)
{
string txt = "http://www.naver.com";
string contents = StringExtension.TextFromUrl(txt);
Console.WriteLine(contents);
}
}
static class StringExtension
{
public static string TextFromUrl(string txt)
{
WebClient wc = new WebClient();
return wc.DownloadString(txt);
}
}
50. C# 3.0 – 확장 메서드 (3)
•
쿼리 구문과 메서드 기반 구문
var all = from p in people
select p;
var all = people.Select(delegate(Person p) { return p; });
var all = from p in people
select new { Name = p.Name, Age = p.Age };
var all = people.Select(delegate(Person p)
{
return new { Name = p.Name, Age = p.Age };
});
51. C# 3.0 – 확장 메서드 (4)
•
SELECT * FROM people WHERE Age >= 30
var all = from p in people
where p.Age >= 30
select p;
var all = people.Where (delegate(Person p) { return p.Age >= 30; })
.Select(delegate(Person p) { return p; });
52. C# 3.0 – 확장 메서드 (5)
•
SELECT * FROM people ORDER BY Age
var all = from p in people
orderby p.Age
select p;
var all = people.OrderBy(delegate(Person p) { return p.Age; })
.Select (delegate(Person p) { return p; });
53. C# 3.0 – 람다 식 (1)
•
추론을 통해 delegate 익명 메서드를 개선
delegate void Functor(object obj);
Functor logOutput = delegate(object obj) { Console.Write(obj); };
Functor logLambda = (obj) => { Console.Write(obj); };
IL
BCL
언어 표현
-
-
O
55. C# 3.0 – 람다 식 (3)
•
메서드 기반 쿼리를 단순화
var all = people.Select(delegate(Person p) { return p; });
var all = people.Select(p => p);
var all = people.Select(delegate(Person p)
{
return new { Name = p.Name, Age = p.Age };
});
var all = people.Select(p => new { Name = p.Name, Age = p.Age });
56. C# 3.0 – 람다 식 (4)
•
데이터로써의 람다 Expression Tree
[코드]
Func<int, int, int> exp = (a, b) => a + b;
[데이터]
Expression<Func<int, int, int>> exp = (a, b) => a + b;
[mscorlib 어셈블리]
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2)
57. C# 3.0 – 람다 식 (5)
•
Expression Tree
// 람다 식 본체의 루트는 2항 연산자인 + 기호
BinaryExpression opPlus = exp.Body as BinaryExpression;
Console.Write(opPlus.NodeType); // 출력: Add
// 2항 연산자의 좌측 연산자의 표현식
ParameterExpression left = opPlus.Left as ParameterExpression;
Console.Write(left.NodeType + ": " + left.Name); // 출력: Parameter: a
// 2항 연산자의 우측 연산자의 표현식
ParameterExpression right = opPlus.Right as ParameterExpression;
Console.Write(right.NodeType + ": " + right.Name); // 출력: Parameter: b
58. C# 3.0 – 람다 식 (6)
•
Expression Tree 컴파일
Expression<Func<int, int, int>> exp = (a, b) => a + b;
var addFunc = exp.Compile();
Console.WriteLine(addFunc(5, 6));
59. C# 3.0 – 람다 식 (7)
•
사례 1) SQL 쿼리를 생성
Expression<Func<IOrderedEnumerable<Person>>> func =
() => from p in people
orderby p.Age descending
select p;
SELECT * FROM people ORDER BY Age DESC
60. C# 3.0 – 람다 식 (8)
•
사례 2) 공용 속성 이름
private int age = 0;
public int Age
{
get
{
return age;
}
set
{
age = value;
OnPropertyChanged(() => this.Age); //
}
}
OnPropertyChanged(“Age”);
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged<TValue>(Expression<Func<TValue>> propertySelector)
{
if (PropertyChanged != null)
{
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(memberExpression.Member.Name));
}
}
}
64. C# 4.0 – 선택적 매개 변수 (1)
• C++의 디폴트 매개 변수
class Person
{
public void Output(string name, int age = 0, string address = "Korea")
{
Console.Write(string.Format("{0}: {1} in {2}", name, age, address));
}
}
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.Output("Anders");
p.Output("Winnie", 36);
p.Output("Tom", 28, "Tibet");
}
}
IL
BCL
언어 표현
O
-
-
65. C# 4.0 – 선택적 매개 변수 (2)
• 확장된 IL 구문
.method public hidebysig instance void Output(string name,
[opt] int32 age, [opt] string address) cil managed
{
.param [2] = int32(0x00000000)
.param [3] = "Korea"
.maxstack 8
IL_0000: nop
...[생략]…
IL_0019: ret
}
66. C# 4.0 – 명명된 인자
• 인자의 이름으로 호출 측에서 값 전달
class Person
{
public void Output(string name, int age = 0, string address = "Korea")
{
Console.Write(string.Format("{0}: {1} in {2}", name, age, address));
}
}
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.Output(address: "Tibet", name: "Tom");
p.Output(age: 5, name: "Tom", address: "Tibet");
p.Output(name: "Tom");
}
}
IL
BCL
언어 표현
-
-
O
67. C# 4.0 – dynamic (1)
• 실행 시에 결정되는 타입
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
dynamic d = 5;
int sum = d + 10;
Console.WriteLine(sum);
}
}
}
IL
BCL
언어 표현
-
O
O
68. C# 4.0 – dynamic (2)
• 결국은 object 타입
using System;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;
class Program
{
public static CallSite<Action<CallSite, object>> p__Site1;
static void Main()
{
dynamic d = 5;
static void Main()
{
object d = 5;
if (p__Site1 == null)
{
p__Site1 = CallSite<Action<CallSite, object>>.Create(
Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded,
"CallTest", null, typeof(Program),
new CSharpArgumentInfo[] {
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
p__Site1.Target(p__Site1, d);
d.CallTest();
}
}
}
69. C# 4.0 – dynamic (3)
• IronPython과 C#
1. NuGet 콘솔을 열고,
2. “Install-Package IronPython” 명령어 실행
using System;
using IronPython.Hosting;
class Program
{
static void Main(string[] args)
{
var scriptEngine = Python.CreateEngine();
string code = @"
print 'Hello Python'
";
scriptEngine.Execute(code);
// 'Hello Python' 문자열 출력
}
}
70. C# 4.0 – dynamic (4)
• C#에서 IronPython 메서드 연동
using System;
using IronPython.Hosting;
class Program
{
static void Main(string[] args)
{
var scriptEngine = Python.CreateEngine();
var scriptScope = scriptEngine.CreateScope();
string code = @"
def AddFunc(a, b):
print 'AddFunc called'
return (a + b)
";
scriptEngine.Execute(code, scriptScope);
dynamic addFunc = scriptScope.GetVariable("AddFunc");
int nResult = addFunc(5, 10);
Console.WriteLine(nResult);
}
}
71. C# 4.0 – dynamic (5)
• IronPython에서 C# 메서드 연동
using System;
using System.Collections.Generic;
using IronPython.Hosting;
class Program
{
static void Main(string[] args)
{
var scriptEngine = Python.CreateEngine();
var scriptScope = scriptEngine.CreateScope();
List<string> list = new List<string>();
scriptScope.SetVariable("myList", list);
string code = @"
myList.Add('my')
myList.Add('python')
";
scriptEngine.Execute(code, scriptScope);
foreach (var item in list)
{
Console.WriteLine(item);
}
}
}