모든 메서드는 호출시에 JIT 컴파일되며 그 결과(native code)는 프로그램의 ‘데이타가 저장되는 Managed Heap’과 전혀 다른 JIT Code Heap 영역에 저장된다. JIT 컴파일된 코드 영역은 (비록 메모리가 모자라 Paging을 할 수는 있으나) Code Heap에서 프로그램이 종료될 때까지(좀 더 정확히 AppDomain이 종료될 때까지) Clear되지 않는다. 이 영역은 GC가 관리하지 않는 영역이며, 관리할 수 없는 영역이다.
CLR은 기본적으로 Optimiazation의 일환으로 클래스 필드의 순서를 자동으로 변경하는데 이것을 Auto Layout이라 부른다. Auto Layout은 Managed Memory 상에서 클래스 필드의 순서를 자동으로 재배치한다.
class와 같은 참조 타입은 디폴트로 Auto Layout을 사용한다.
struct와 같은 값 타입은 디폴트로 Squential Layout을 사용한다.
[StructLayout(LayoutKind.Explicit, Pack = 1)] 과 같이 사용해서 Managed Memory 상에서 필드에 저장된 [FieldOffset()] 속성에 따라 메모리 위치가 설정된다.
[StructLayout(LayoutKind.Explicit, Pack = 1)]classMyClass{ [FieldOffset(0)]publicinti; [FieldOffset(4)]publicdoubled; [FieldOffset(12)]publicbyteb;}// MyClass 라는 클래스에 Explicit 레이아웃을 사용하여 // 필드 i 가 처음에, 필드 d가 4번째 바이트 위치에, 필드 b가 12번째에 각각 위치하게 됨을 지정하고 있다.
structEmployee{publicstringName{get;set;}publicintSalary{get;set;}}classHR{publicvoidRaiseSalary(Employeeemp){emp.Salary=emp.Salary+1000;// struct는 값형식이므로 여기서 올린 Salary는// 복제본의 Salary이다. // 따라서 원본이 변하지는 않는다. }}classMain{publicvoidRun(){Employeeemp=newEmployee();emp.Name="Lee";emp.Salary=9000;HRhr=newHR();Console.WriteLine(emp.Salary);// 인상전 9000hr.RaiseSalary(emp);Console.WriteLine(emp.Salary);// 인상후 9000 ???}}
publicinterfaceIAdd{voidAddOne();}structMyValue:IAdd{intvalue;publicintValue=>value;publicMyValue(intvalue){this.value=value;}publicvoidAddOne(){value++;}}classMain{publicvoidRun(){MyValuev1=newMyValue(3);v1.AddOne();Console.WriteLine(v1.Value);// 4. 좋다.MyValuev2=newMyValue(3);IAdditf=v2asIAdd;itf.AddOne();Console.WriteLine(v2.Value);// 3. ???// struct는 값 형식이다.// 그래서 인터페이스로 박싱하면 (값 -> 참조) // 스택에 있던 값이 힙으로 복사되고, 힙에 있는 값이 증가된다. // 그래서 기존 스택의 값을 출력하면 그대로이다. }}
classAnimal{publicvoidEat(intkg){Console.WriteLine("Animal.Eat: {0} kg",kg);}}classDog:Animal{publicvoidEat(longkg){Console.WriteLine("Dog.Eat: {0} kg",kg);}}classBulldog:Dog{publicvoidEat(stringkg){Console.WriteLine("Bulldog.Eat: {0} kg",kg);}}classMain{publicvoidRun(){Bulldogbulldog=newBulldog();intkg=2;bulldog.Eat(kg);// Dog.Eat() 호출((Animal)bulldog).Eat(kg);// Animal.Eat() 호출// 메서드 검색은 동일 메서드 명으로// 동일 타입 or 호환 가능한 타입의 파라미터를 발견할 때까자// 상위 클래스를 찾아 가면서 진행된다. // 그래서 일단 중간에 조건에 맞는 메서드를 발견하면 검색을 중지하고 // 해당 메서드를 사용한다. // 특정 메서드를 지정해서 호출하고 싶다면,// 해당 클래스로 캐스팅할 후 메서드를 호출하면 된다.}}
classDataSet{publicList<DataTable>Tables=newList<DataTable>();}classDataTable{publicList<string>Columns=newList<string>();}classMain{publicvoidAddTable(DataSetds)// ref로 해야 함. {DataSetnewDs=newDataSet();DataTabledt=newDataTable();dt.Columns.Add("ColA");newDs.Tables.Add(dt);ds=newDs;// ds 내부의 멤버를 변경할 순 있지만, // 다른 새로운 레퍼런스 객체를 할당할 순 없다. // 그래서 참조형식인 class도 ref를 사용해야 한다. }publicvoidRun(){DataSetds=newDataSet();AddTable(ds);Console.WriteLine(ds.Tables.Count);// 0이 나온다. ???}}