728x90

컴파일러에게 변수의 Type을 체크하지 않도록 하고

런타임시까지는 해당 타입을 알 수 없음을 표시

// 1. dynamic은 중간에 형을 변환할 수 있다.

dynamic v = 1;
// System.Int32 출력
Console.WriteLine(v.GetType());

v = "abc";
// System.String 출력
Console.WriteLine(v.GetType());

=====================================
// 2. dynamic은 cast가 필요없다
object o = 10;

// 틀린표현
// (에러: Operator '+' cannot be applied to operands of type 'object' and 'int')
o = o + 20;

// 맞는 표현: object 타입은 casting이 필요하다
o = (int)o + 20;

// dynamic 타입은 casting이 필요없다.
dynamic d = 10;
d = d + 20;

 

익명타입 객체를 dynamic 에 할당하고 이를 다른 클래스 메서드에 파라미터로 전달하는 예시

- 문제1 : 익명타입은 한번 생성된 후 다시 새로운 속성을 추가할 수 없다

- 문제2 : 익명타입 자체가 메서드 이벤트 등을 갖지 못함

// 동일 어셈블리에서 익명타입에 dynamic 사용한 경우
class Class1
{
    public void Run()
    {
        dynamic t = new { Name = "Kim", Age = 25 };
        var c = new Class2();        
        c.Run(t);
    }
}

class Class2
{
    public void Run(dynamic o)
    {
        // dynamic 타입의 속성 직접 사용
        Console.WriteLine(o.Name);
        Console.WriteLine(o.Age);
    }
}

 

ExpandoObject : dynamic 타입에 속성, 메서드, 이벤트를 동적으로 쉽게 할당할 수 있게 도와주는 클래스

dynamic 타입을 쉽게 생성하도록 도와주는 ExpandoObject 클래스

보다 유연한 Customization을 위한 고급 dynamic 기능을 지원하는 DynamicObject 클래스가 있는데

여기선 ExpandoObject 를 보자.

//ExpandoObject
public class Myclass
{
    public void M1()
    {
        // ExpandoObject에서 dynamic 타입 생성
        dynamic person = new ExpandoObject();

        // 속성 지정
        person.Name = "Kim";      
        person.Age = 10;

        // 메서드 지정
        person.Display = (Action)(() =>
        {
            Console.WriteLine("{0} {1}", person.Name, person.Age);
        });

        person.ChangeAge = (Action<int>)((age) => { 
            person.Age = age;
            if (person.AgeChanged != null)
            {
                person.AgeChanged(this, EventArgs.Empty);
            }
        });

        // 이벤트 초기화
        person.AgeChanged = null; //dynamic 이벤트는 먼저 null 초기화함

        // 이벤트핸들러 지정
        person.AgeChanged += new EventHandler(OnAgeChanged);

        // 타 메서드에 파라미터로 전달
        M2(person);
    }

    private void OnAgeChanged(object sender, EventArgs e)
    {
        Console.WriteLine("Age changed");
    }

    // dynamic 파라미터 전달받음
    public void M2(dynamic d)
    {
        // dynamic 타입 메서드 호출 
        d.Display();
        d.ChangeAge(20);
        d.Display();
    }
}

 

ExpandoObject의 dynamic 멤버 보기

ExpandoObject 클래스는 동적으로 추가되는 멤버들을 내부 해시테이블에 저장하고 있는데, 필요한 경우 이 정보를 IDictionary<String, Object> 인터페이스를 통해 쉽게 엑세스할 수 있다.

 

즉, ExpandoObject 클래스 자체가 IDictionary<String, Object> 인터페이스 구현하고 있어서 이 클래스 객체를 IDictionary<String, Object> 인터페이스로 캐스팅하여 내부 멤버 데이타를 엑세스할 수 있다.

 

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

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            M11 aa = new M11();
            aa.M1();
        }
    }

    class M11
    {
        public void M1()
        {
            dynamic person = new ExpandoObject();
            person.Name = "Kim";
            person.Age = 10;
            person.Display = (Action)(() => { });
            person.ChangeAge = (Action<int>)((age) => { person.Age = age; });
            person.AgeChanged = null;
            person.AgeChanged += new EventHandler((s, e) => { });

            // ExpandoObject를 IDictionary로 변환
            var dict = (IDictionary<string, object>)person;

            // person 의 속성,메서드,이벤트는
            // IDictionary 해시테이블에 저정되어 있는데
            // 아래는 이를 출력함
            foreach (var d in dict)
            {
                Console.WriteLine("{0}: {1}", d.Key, d.Value);
            }
        }
    }
}

 

728x90

+ Recent posts