02 뇌를자극하는c# 특수기능

23 분 소요

예외처리

try{} catch(){} finally{}

Code
		{
            try
            {
                int v1 = 10, v2 = 0;
                v1 = v1 / v2;
                Console.WriteLine("finished");
            }
            catch(DivideByZeroException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.StackTrace);                
            }
            finally
            {
                Console.WriteLine("finished");
            }
		}


finally 내에서 예외가 발생하면 터짐. 안에 또 try ... catch 문을 넣던가 해야함.

예외부분과 로직부분이 분리되어 깔끔한 처리가 가능해짐.

Delegate

Code
    delegate void DelFunc(int a, int b);
    class A
    {
        public void Plus(int a, int b) { Console.WriteLine(a + b); }
    }
    class Program
    {
        static void Main(string[] args)
        {
            DelFunc func = null;
            A a = new A();

            // new 로 할당
            func = new DelFunc(a.Plus) + new DelFunc(a.Plus);
            // Delegate. 로 할당 및 추가 및 제거
            func = Delegate.Combine(new DelFunc(a.Plus), new DelFunc(a.Plus)) as DelFunc;
            func = Delegate.Remove(func, new DelFunc(a.Plus)) as DelFunc;
            // +=, -= 로 추가 및 제거
            func -= a.Plus; func += a.Plus;
            // 익명메소드
            func = delegate (int a, int b) { Console.WriteLine(a+b); };
            // 익명함수
            func = (a, b) => Console.WriteLine(a+b);
        }
    }


Delegate

[한정자] delegate [return type] [Name] (params);

  • 이때 정적 메소드는 함수이름을 그대로 쓰면 되고
  • 인스턴스 메소드의 경우 instance.Func 이렇게 넣으면 인스턴스가 자동으로 캡쳐됨.
  • delegate int Compaire<T>(T a, T b); 처럼 제너릭도 가능.

  • Delegate Chain 으로 메소드를 추가하고 제거할 수 있음.

Event

[한정자] event delegate [DelegateName];

Delegate 와 차이는 public 등오로 외부에서 접근 시 호출이 불가능 하다는 것.

Lambda

Anonymous Method

  • delegate (int a, int b) { return a+b; }
  • Parameter 내용과 return 타입을 맞추어 바로 할당가능.
  • C# 2.0 에 도입되어 호환을 위해 남아있음

Anonymous Funcion

  • DelFunc func = (a, b) => a + b;
  • Type Inference 로 Parameter 의 타입을 안적어도 됨
  • 여러 statement 로 내용을 만들려면 => 이후에 중괄호를 넣으면 됨.
  • C# 3.0 에 도입되어 권장됨

미리 정의된 Delegate

Func<in T1, in T2 ... out T_R>

  • 리턴값이 맨 뒤에 있고 앞에 있는건 다 인자로, 최대 16 개가 들어옴.
  • 파라미터가 ref, in, out 등으로 수식되는 경우가 아니면 왠만한건 커버됨.

Action<in T1, in T2 ... out T_R>

  • 리턴값 없음

LINQ

Language INtegrated Query 의 약자로 쿼리임.

Code
    struct Data {
        public string Name { get; set; }
        public int[] Log { get; set; }

        public Data(int[] log) 
        {
            const string characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            Random rd = new Random();
            Name = new string(Enumerable.Repeat(characters, 8).Select(s => s[rd.Next(s.Length)]).ToArray());
            Log = log; 
        }
    }
    
    class Datas : IEnumerable<Data>, IEnumerator<Data>
    {
        Data[] datas;
        int pos = -1;
        public Datas(int size) { datas = new Data[size]; }
        public Data this[int idx]{ get { return datas[idx];} set { datas[idx] = value;}} 
        public Data Current => datas[pos];
        object IEnumerator.Current => datas[pos];

        public void Dispose() { }

        public bool MoveNext()
        {
            return ++pos < datas.Length;
        }

        public void Reset()
        {
            pos = -1;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            for (int i = 0; i < datas.Length; i++)
                yield return datas[i];
        }

        IEnumerator<Data> IEnumerable<Data>.GetEnumerator()
        {
            for (int i = 0; i < datas.Length; i++)
                yield return datas[i];
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            int[] dd = new int[] { 1, 2, 3 };
            Datas datas = new Datas(100);
            for(int i = 0; i < 100; i++)
                datas[i] = new Data(new int[]{ i * 3, i * 3 + 1, i * 3 + 2 });
            
            var res = from d in datas
                          from s in d.Log
                          where s % 2 == 0
                      where s < 50
                      orderby d.Name
                      group s by d.Name[0] into c
                      select new { Key = c.Key, Var = c};
            
            foreach (var g in res)
            {
                Console.WriteLine("Group : {0}", g.Key);
                foreach(var v in g.Var)
                    Console.WriteLine(v);
            }
        }
    }


원리

// select d from datas
// orderby d.Name
// select new { Name = d.Name, Var = d.Log };

datas.Where(d => d.Log[0] % 2 == 0)
	.OrderBy(d => d.Name)
	.Select(new {Name = d.Name, Var = d.Log} );     
    

LINQ 쿼리식은 System.Linq 에서 정의된 IEnumerable<T> 의 확장 메소드인 표준 LINQ 연산 메소드 중에 하나임.

  • from ~ in 위에 오는 Container 는 IEnumerable<T> 를 상속해야하는 이유임.
  • 결과값이 쿼리문에 따라서 IEnumerable<T>, IOrderbyEnumerable<T> 등으로 나오는 것도 이러한 확장 메소드를 살펴보면 됨.
  • 모든 표준 LINQ 연산 메소드가 쿼리식으로 가능한게 아니므로 둘을 섞어 써야함.

기본적 연산자

orderby

  • 오름차순이며 내림차순은 뒤에 descending 를 붙여야함

select

  • 리턴값의 형식 매개 변수 는 여기서 결정됨.
  • select new { Name = d, Var = d }; 처럼 무명형식 역시 사용가능함.

group by

중첩된 from

Code
from c in datas
  from s in c.Score
  where s < 60
select new { v1 = c, v2 = s };


이중 포문을 도는 것이랑 같음.

Join

from d1 in data1
join d2 in data2 on d1.Name == d2.Name into ps  
from r2 in ps.DefaultIfEmpty(new Data2("N/A"))
select new { Name = r2.Name, v1 = d1.X, v2 = r2.Y };

join 은 기본적으로 nateral join 을 처리함.

  • 위의 코드에서 a, b 는 join 된 결과만 처리됨.
  • 그냥 쿼리문이면 select a from (A natural join B) 임에 참고.

하지만 DefaultIfEmpty() 를 수행하면 LeftJoin 까지 가능함 (나머지 Outer Join 은 불가능)

  • 위의 경우 d1 과 매치되지 않는 d2DefaultIfEmpty() 로 생성한 것으로 대체됨.

Meta Data

Reflector

메소드 반환형식 설명
GetConstructor() ConstructorInfo[] 해당 형식의 모든 생성자 목록을 반환합니다.
GetEvents() EventInfo[] 해당 형식의 모든 이벤트 목록을 반환합니다.
GetFields() FieldsInfo[] 해당 형식의 모든 필드 목록을 반환합니다.
GetGenericArguments() Type[] 해당 형식의 형식 매개 변수 목록을 반환합니다.
GetInterfaces() Type[] 해당 형식이 상속하는 인터페이스 목록을 반환합니다.
GetMembers() MemberInfo[] 해당 형식의 모든 멤버 목록을 반환합니다.
GetMethods() MethodInfo[] 해당 형식의 메소드 목록을 반환합니다.
GetNestedTypes() Type[] 해당 형식의 내장 형식 목록을 반환합니다.
GetProperties() PropertyInfo[] 해당 형식의 모든 프로퍼티 목록을 반환합니다.

System.Reflection.BindingFlags 의 열거형을 통해 위 함수의 검색조건을 처리가능하고, 기본은 public 등의 옵션이 처리됨.

Sytem.Type 을 얻는 방법

  • typeof([TypeName])
  • Type.GetType(["TypeName include Namespace"])

System.Type 으로 인스턴스 생성

  • Activator.CreateInstance(type)
  • Activator.CreateInstance<T>()

PropertyInfo.SetValue(instance, value, index)

MethodInfo.Invoke(instance, param)

Attribute

[AttributeName(Attribute Parameter)]
public void Method()
{

}

위처럼 Method 뿐만 아니라 Field 등 여러 요소 앞에 적어주면 됨.

| Attribute | 설명 | |:————|:——-| |[Obsolute(WarningMessage)]| 컴파일러에게 사용시 Deprecated 같은 경고 | |[DllImport]| C, Cpp 같은 native dll 호출| |[Serializable]| BinaryFormmater 를 이용한 Serialize() 가능. cf. [NonSerialized] | |[Flags] | 열거형에 붙어서 flag 연산을 가능하게 함 | System.Attribute 를 상속한 클래스로 커스터마이즈 가능.

dynamic

런타임에 type 을 검사하며, 같은 method 이름이면 처리해줌.

RCW(Runtime Callable Wraper), 등에서 쓰므로 건들지 말자.

Thread

Abort() 를 쓰면 자원 소유권 취소 등 절대로 취소되면 안되는 작업 중에도 중단시켜 권장되지 않고, Interrupt()WaitSleepJoin 상태에서만 중단시켜 괜찮음.

lock( reference object ) {}

  • 파라미터에 this, Type, string, public field 는 다른 스레드에서 접근시 쓸데없이 동기화를 해야하므로 권장되지 않음.
  • Monitor.Enter()Monitor.Exit() 으로 구현되어 있음.
Monitor.Enter(obj)
try
{
	cnt++;
}
finally
{
	Monitor.Exit(obj);
}

System.Threading.TasksThread 클래스로 구현되었으며, 쪼개진 작업들을 동시에 처리하는 코드와 비동기 코드를 위해 설계됨.

  • Task.Factory.StartNew( ()=>1+1;)

Parallel.For(from, to, Method)

  • 범위기반 여러 동작을 확인할 때 알아서 스레드를 배분해서 처리함

GC

지침

  1. 객체를 너무 많이 만들지 마세요.
  2. 너무 큰 객체 할당은 피하세요.
    • LOH(Large Object Heap) 와 SOH(Small Object Heap) 이 있음
    • SOH 는 GC 후 객체들을 모아 단편화를 막음
    • LOH 는 그냥 냅둬 단편화가 있을 수 있고, 2세대 Heap 으로 간주되어 0, 1 세대랑 같이 GC 를 돌아 매우 느림.
  3. 너무 복잡한 참조 관계는 만들지 마세요
    • Heap 의 세대가 바뀌면 주소가 바뀌고 참조 객체의 주소다 다 바꾸어야함. 참조관계가 복잡하면
    • 참조관계를 최소한으로 만들면 Write Barrier 를 적게 만들어 오버헤드를 줄임.
  4. 루트를 너무 많이 만들지 마세요.

댓글남기기