Programming/C#

C# 2.0 변경점(2) - yield return/break, partial class, Nullable, 익명 메서드, 정적 클래스

lee308812 2019. 3. 31. 16:44

[ yield return/break ]

- "yield return", "yield break" 예약어를 이용하면 기존의 IEnuerable, IEnumerator 인터페이스를 이용해 구현했던 열거 기능을 쉽게 구현할 수 있다.

 

- IEnumerable을 이용해서 아래와 같이 무한 집합을 구현할 수 있다.

using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApp1
{
    // 1부터 자연수를 무한하게 출력(int 범위)
    public class NaturalNumber : IEnumerable<int>
    {
        public IEnumerator<int> GetEnumerator()
        {
            return new NaturalNumberEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new NaturalNumberEnumerator();
        }
    }

    public class NaturalNumberEnumerator : IEnumerator<int>
    {
        int _current;

        public int Current
        {
            get { return _current; }
        }

        object IEnumerator.Current
        {
            get { return _current; }
        }

        public void Dispose() { }

        public bool MoveNext()
        {
            _current++;
            return true;
        }

        public void Reset()
        {
            _current = 0;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            NaturalNumber number = new NaturalNumber();

            foreach(int n in number)
            {
                Console.WriteLine(n);
            }
        }
    }
}

 

- 구현이 번거로운데, yield를 이용해 다음과 같이 간단하게 바꿀 수 있다.

using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApp1
{
    // 1부터 자연수를 무한하게 출력(int 범위)
    public class YieldNaturalNumber
    {
       public static IEnumerable<int> Next()
        {
            int _start = 0;

            while(true)
            {
                _start++;
                yield return _start;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            foreach(int n in YieldNaturalNumber.Next())
            {
                Console.WriteLine(n);
            }
        }
    }
}

 

- Next 메서드가 호출되면 yield return에서 값이 반환되면서 메서드가 중단된다. 다음에 다시 메서드가 호출되면 yield return이 실행된 코드의 다음 줄부터 실행을 재개한다고 이해하면 된다. (실제 내부 구현은 원래 예제와 유사하게 치환됨)

 

 

[ Partial class ]

- partial 예약어를 클래스에 적용하면 클래스의 소스코드를 2개 이상으로 나눌 수 있다.

- 한 파일에 있어도 되고, 다른 파일로 나눠도 되지만 반드시 같은 프로젝트에서 컴파일 해야 한다. C# 컴파일러는 빌드 시에 같은 프로젝트에 있는 partial 클래스를 하나로 모아 단일 클래스로 빌드한다.

using System;

namespace ConsoleApp1
{
    partial class Person
    {
        string _name;
        public string Name { get { return _name; } set { _name = value; } }
    }

    partial class Person
    {
        int _age;
        public int Age { get { return _age; } set { _age = value; } }
    }
}

[ nullable 형식 ]

- System.Nullable<T> 구조체를 의미하며 일반적인 값 형식에 대해서 null 표현이 가능하게 하는 역할을 한다. 

(bool type의 결혼 여부 변수에서 입력을 아예 안한다면??)

 

- Nullable<bool>을 bool?로 축약하여 쓸 수도 있다.

using System;

namespace ConsoleApp1
{
    public class SiteMember
    {
        bool _getMarried;

        public bool GetMarried
        {
            get { return _getMarried; }
            set { _getMarried = value; }
        }
    }

    public class SiteMemberNullAble
    {
        Nullable<bool> _getMarried;

        public Nullable<bool> GetMarried
        {
            get { return _getMarried; }
            set { _getMarried = value; }
        }
    }

    public class SiteMemberNullAble2
    {
        bool? _getMarried; // Nullable<bool>의 축약형

        public bool? GetMarried
        {
            get { return _getMarried; }
            set { _getMarried = value; }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SiteMemberNullAble m1 = new SiteMemberNullAble();

            Console.WriteLine(m1.GetMarried == null);   // true
            Console.WriteLine(m1.GetMarried.HasValue);

            m1.GetMarried = true;
            Console.WriteLine(m1.GetMarried == null);   // false
            Console.WriteLine(m1.GetMarried.HasValue);
        }
    }
}

 

[ 익명 메서드 ]

- 델리게이트에 전달되는 메서드가 일회성으로만 필요할 때 편의상 사용된다.

- 실제 컴파일 될 때는 중복되지 않을 특별한 문자열을 하나 생성해 메서드를 만든다.

using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread thread = new Thread(delegate (object obj)
            {
                Console.WriteLine("ThreadFunc in anonymous method called!");
            });

            thread.Start();
            thread.Join();
        }
    }
}

- 익명 메서드를 델리게이트 타입의 변수에 담아 재사용하는 것도 가능하다.

using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        delegate int? MyDivide(int a, int b);

        static void Main(string[] args)
        {
            MyDivide myFunc = delegate (int a, int b)
            {
                if (b == 0) return null;

                return a / b;
            };

            Console.WriteLine("10 / 2 == " + myFunc(10, 2));
            Console.WriteLine("10 / 0 == " + myFunc(10, 0)); // null
        }
    }
}

 

[ 정적 클래스 ]

- static class로 정의하여 static 멤버만 내부에 포함할 수 있다. 인스턴스 멤버를 포함할 필요가 없다는 사실을 명시하기 위해서 사용한 것이다.

- 예시로는 System.Math 타입이 있다.

 

 

- 출처 : 시작하세요! C# 7.1 프로그래밍(위키북스), 정성태님 저