.net framework 역사

1.0 

  • 2002년 - C#1.0, Managed Code, Visual Studio 2002
  • 어트리뷰트 : 속성을 쉽게 부여, 런타임시 필요한 정보들을 전달

    [Conditional("DEBUG")] // DEBUG시 사용되는 메소드
    [DllImport("User32.Dll")] //Win32 API DLL 사용시
    [Obsolete("오래된 버전입니다.")] // 사용을 권장하지 않는 메소드
  • 델리게이트 : 안전한 함수포인터, 연산자(+=, -=)
  • 리플렉션 : 런타임에서 객체의 멤버를 조회하고 실행도 가능

    - typeof 연산자 : 클래스 타입으로 접근할 때 사용
    - System.Object의 GetType() : 객체명으로 접근할 때 ==> 객체.GetType();
    - Type.GetType() : 네임스페이스로 접근할 때 사용
    - Assembly.LoadFrom() :  dll 파일에 직접 접근할 때 사용
  • 값형&참조형간의 박싱 & 언박싱 : 최상위 객체 object 타입 소개, 스택에 값형, 힙에 참조형, 값을 객체로 포장시 boxing

  • foreach : 반복문
  • 프로퍼티 / 인덱서 : Get/Set 메서드 대신 직관적으로 사용

    // Property
    private string name;
    public string Name
    {
        get { return "저는 " + name + "입니다"; } // 로직 구현도 가능
        protected set { name = value; } // set에는 다른 접근제한
    }
    
    // Auto Property (C# 3.0 이후 지원)
    public double Value { get; set; }
    // 인덱서를 this를 통해 구현
    class MyClass{
        private int[] array = new int[5]; 
        public int this[int i]
        {
            get { return array[i]; }
            set { array[i] = value; }
        }
    }
    
    // 다른 클래스에서 사용시
    MyClass myClass = new MyClass();
    myClass[0] = 100;
    Console.WriteLine(myClass[0]);
    // 인덱서에서 첨자를 문자열을 사용
    class NickName{
        private Dictionary<string, string> names = new Dictionary<string, string>();
        public string this[string realName]
        {
            get { return names[realName]; }
            set { names[realName] = value;  }
        }
    }
    
    // 다른 클래스에서 사용시
    NickName nickName = new NickName();
    nickName["star"] = "KimStar";
    Console.WriteLine(nickName["star"]);

1.1

  • 2003년 - C#1.1,  1.0의 버그픽스

2.0

  • 2005년 - C#2.0, ASP.NET 2.0, ADO.NET 2.0, Windows Form 2.0, Click Once, Generic
  • 제네릭 : 어떤 타입이든 될 수 있는 타입

    // 제네릭 이전 - ArrayList에는 object만 사용가능함
    ArrayList oldList = new ArrayList();
    oldList.Add(1); // boxing 
    int a = (int)oldList[0]; // unboxing
    
    // 제네릭 이후
    List<int> newList = new List<int>();
    newList.Add(1); // boxing 안함
    int b = newList[0]; // unboxing 안함
  • 익명메소드와 클로저 : 코드블록을 독립적으로 사용할 수 있으며, 코드블럭에서 바깥의 지역변수 사용 가능

    // 기존 위임자 사용시
    void DisplayString(string s) { ... }
    delegate void MyDelegate(string s);
    MyDelegate func1 = new MyDelegate(DisplayString);
    MyDelegate func2 = DisplayString;
    
    // 익명메소드 사용시
    MyDelegate func3 = new Mydelegate(
         delegate(string s) {
               Console.WriteLine("string");
         }
    )
    
    // 익명메소드 더 간단히
    MyDelegate func4 = delegate(string s) {
         Console.WriteLine("string");
    };
    int[] nums = new int[] {1,2,3,4,5,6,7,8,9,10};
    int factor = 3; 
    // 클로저 : 익명메소드 안에서 바깥의 factor를 사용
    // Predicate : 조건을 정의
    Predicate<int> isPowerOfNum = delegate(int num) { return num % factor == 0; };
    
    int[] result = Array.FindAll(nums, isPowerOfNum);
    foreach (int num in result)
    {
     Console.Write(" {0}", num);
    }
  • 반복자 : IEnumerable<T> 는 값이 요청될때마다 구해서 가져옴
    static void Main(string[] args)
    {
        int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        foreach (int num in GetPowerOfNum(nums, 2))
        {
            Console.Write(" {0}", num);
        }
    }
    
    public static IEnumerable<int> GetPowerOfNum(int[] nums, int factor)
    {
        for (int i = 0; i < nums.Length; i++)
        {
            if (nums[i] % factor == 0)
            {
                Console.Write(" yield! ");
                // yield : iterator 블록에서 열거자 개체에 값을 제공하거나 반복이 끝났음을 알리기 위해 사용
                yield return nums[i];
            }
        }
    }
    
    출력 : yield!  2 yield!  4 yield!  6 yield!  8 yield!  10
  • Partial Type : 클래스를 여러 파일에 나눔,
  • 널 가능타입 : 참조형은 null 선언 가능하지만, 값형은 빈값이라도 반드시 가졌어야 했음. null value propagation 지원 (a.b().c() 에서 b()가 null 이면 c()도 null)

    // int인데 null 가능
    int? num = null;
    // Null Value Propagation : null에 ToString메소드를 실행해도 예외없이 null
    Console.WriteLine(num.ToString()); 
    
    출력 : 없음

3.0

  • 2006년 - WPF, WCF, WF, CardSpace
  • 암시적인 타입을 적용한 지역변수: var 타입, 컴파일러가 타입을 유추
  • 익명 타입 : LINQ 중간과정에 생기는 타입을 class로 정의하지 않고 익명타입으로 사용함..

    int num = 2;
    string[] names = { "옴니아", "아이폰" };
    
    // 암시적인 타입 : var를 통해 컴파일러가 타입을 유추
    // 익명타입 : new 뒤에 빈칸 --> names의 값들을 받아서 임시로 타입을 만듬  
    // --> {num=2,name="옴니아",numName="옴니아 3"},{num=3,name="아이폰",numName="아이폰 4"}
    var pairs = names.Select(name => new { num = num++, name = name, numName = name + " " + num}).ToList();
    
    foreach (var pair in pairs)
    {
        Console.WriteLine("num:{0}, name:{1}, numName:{2}", pair.num, pair.name, pair.numName);
    }
    
    출력 : 
    num:2, name:옴니아, numName:옴니아 3
    num:3, name:아이폰, numName:아이폰 4
  • 확장메서드 : 기존타입에 추가로 메소드를 추가할때 사용됨. LINQ 사용시 헬퍼메소드 개념으로도 사용.
    public static class ExtensionExam
    {
        public static int GetMiddleNumber(this int[] nums)
        {
            int middleIndex = nums.Count() / 2;
            return nums.ElementAt(middleIndex);
        }
    }
    ...
    int[] nums = new int[] {1,2,3,4};
    Console.WriteLine(nums.GetMiddleNumber()); 
    
    출력 : 3
  • 객체와 컬렉션 초기화 생성자 : 생성자의 파라메터 대신, public 으로 선언된 멤버변수와 프로퍼티에 원하는 만큼 값을 할당 가능

    public class Customer { public string name; public string address; }
    ...
    Customer test = new Customer(name="star", address="일산");
  • 람다와 쿼리 표현식 : 람다는 익명메소드를 다듬은것, 쿼리표현식은 데이터 추출시 쿼리를 작성하는것.

    int[] nums = new int[] {1,2,3,4};
    
    // 쿼리표현식
    IEnumerable<int> num1 = 
        from num in nums
        where (num%2).Equals(0)
        orderby num descending
        select num;
    
    // 미리 정의된 메서드와 람다식의 조합
    IEnumerable<int> num2 = 
        nums.Where(num => (num%2).Equals(0)).OrderByDescending(num=>num); 
    
    // num1과 num2는 같은 결과
  • Expression Tree
  • 자동으로 구현되는 프로퍼티

    // 기존방식
    private int num;
    public int Num 
    { 
       get {return num;}
       set {num = value; }
    }
    
    // C# 3.0 이후 자동구현 프로퍼티
    public int Num2
    {
       get;
       set;
    }

3.5

  • 2007년 - LINQ, C#3.0 (람다식, 확장메서드 지원)

3.5 sp1

  • 2008년 - ASP.NET Dynamic Data, Client Profile

4.0

  • Application Compatibility & Deployment : 새로 만들어진 4.0 (2.0~3.5sp1까지는 2.0 기반) 이지만 2.0, 1.0과 호환
  • Dynamic 타입의 추가
  • Co-Contravariance : 역 공변성
  • Named and Optional Parameters

    public static int Add(int x, int y=8, int z=3)
    {
        return x+y+z;
    }
    ...
    Console.WriteLine(Add(2,6,9));      // x=2, y=6, z=9
    Console.WriteLine(Add(2,6));        // x=9, y=2, z=3
    Console.WriteLine(Add(2));          // x=9, y=8, z=3
    Console.WriteLine(Add(2,z:6,y:9));  // x=2, y=9, z=6
    Console.WriteLine(Add(y:2,x:9));    // x=9, y=2, z=3
    Console.WriteLine(Add(9,z:1));      // x=9, y=8, z=1
  • Parallel Computing
  • .NET Framework Side By Side : 하나의 Process에서 여러버전의 Framework 사용가능
  • TPL (Task Parallel Library) : PLINQ 사용

5.0

  • Caller info attributes
  • Windows Runtime support
  • Asynchronous programming
사용자 삽입 이미지

비동기 프로그래밍

비동기 콜백함수가 많으면 Goto문을 많이 쓰는 것처럼 이해하기 힘든 스파게티 코드가 될 수 있다.
C# 5.0에서는 컨트롤의 흐름을 크게 변화하지 않고 동기를 비동기로 쉽게 변환할 수 있다.

  • 동기 방식 : 5 line에서 download 동안 화면이 멈추고 사용자는 조작 불가한 상태가 된다.

    Movie[] QueryMovies(int year, int first, int count)
    {
        var client = new webClient();
        var url = string.Format(query, year, first, count);
        var data = client.DownloadString(new Uri(url));
        var movies =
            from entry in XDocument.Parse(data).descendants(xa + "entry")
            ~~~
    }
  • 비동기 방식 #1 : 백그라운드 쓰레드 방식으로 코드를 수정하여 비동기로 Donwload를 수행할 수 있다. 하지만 수정을 위한 로직의 변경이 많아진다.

    Movie[] QueryMovies(int year, int first, int count)
    {
        var client = new webClient();
        var url = string.Format(query, year, first, count);
        var data = client.DownloadString(new Uri(url));
        var movies =
            from entry in XDocument.Parse(data).descendants(xa + "entry")
            ~~~
    }
  • 비동기 방식 #2 : TaskAsync 방식으로 코드를 변경하면 기존의 로직에서 큰 변화 없이 비동기 처리가 가능하다.

    async Task<Movie[]> QueryMovies(int year, int first, int count)            // 2. 메소드로 async로 수정
    {
        var client = new webClient();
        var url = string.Format(query, year, first, count);
        var data = await client.DownloadStringTaskAsync(new Uri(url));      // 1. TaskAsync로 수정
        var movies = 
            from entry in XDocument.Parse(data).descendants(xa + "entry")
            ~~~
    }
    // 호출하는 쪽
    async void LoadMovies(int year)                                         // 4. await 추가 
    {
        while(true)
        {
            var movies = await QueryMovies(~~~);                            // 3. 호출하는 곳에 await 추가 
        }
    }

     

댓글 남기기