2018년 6월 12일 화요일

C# - 이름으로 객체 생성

지난번에 이름으로 멤버변수 및 메서드에 접근하는 방법을 살펴보았습니다. 비슷한 방식으로 클래스 이름으로 객체를 만드는 방법 역시 존재합니다.


using System.Reflection;

namespace ClassName
{
    internal class ClassA
    {
        internal void Write()
        {
            Console.WriteLine("ClassA");
        }
    }
    internal class ClassB
    {
        internal void Write()
        {
            Console.WriteLine("ClassB");
        }
    }
}

이와 같은 두개의 클래스가 있습니다. 여기서 클래스 이름("ClassA" 또는 "ClassB"를 가지고 객체를 만들기 위해서는 다음과 같이 할 수 있습니다.

using System.Reflection;

namespace ClassName
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly creator = Assembly.GetExecutingAssembly();
            object obj = creator.CreateInstance("ClassName.ClassA");
            if (obj is ClassA)
                (obj as ClassA).Write();
            obj = creator.CreateInstance("ClassName.ClassB");
            if (obj is ClassB)
                (obj as ClassB).Write();
        }
    }
}

이와 같이 Assembly 객체를 만들고 나서 CreateInstance메서드로 객체를 생성할 수 있습니다. 단, 이 경우에 클래스는 반드시 namespace까지 포함하고 있는 이름이어야 합니다. 이 경우에 Program과 ClassA, ClassB가 같은 namespace에 있으므로 코드에서 객체를 만들 때는 ClassName을 생략할 수 있지만, 문자열로 객체를 만들 때는 생략할 수 없습니다.

또한 CreateInstance의 반환값은 object형이므로 is, as연산자를 통해 형변환 후 작업을 해야겠죠.

using System.Reflection;

namespace ClassName
{
    class Program
    {
        static void Main(string[] args)
        {
            string clsName = Console.ReadLine();
            Assembly creator = Assembly.GetExecutingAssembly();
            object obj = creator.CreateInstance("ClassName." + clsName);
            if (obj is ClassA)
                (obj as ClassA).Write();
            else if (obj is ClassB)
                (obj as ClassB).Write();
        }
    }
}

만약 이런 식으로 형을 하나하나 검사하기 힘들다면 상속관계를 이용할 수 있습니다.


using System.Reflection;

namespace ClassName
{
    internal abstract class ClassBase
    {
        internal abstract void Write();
    }
    internal class ClassA : ClassBase
    {
        internal override void Write()
        {
            Console.WriteLine("ClassA");
        }
    }
    internal class ClassB : ClassBase
    {
        internal override void Write()
        {
            Console.WriteLine("ClassB");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            string clsName = Console.ReadLine();
            Assembly creator = Assembly.GetExecutingAssembly();
            object obj = creator.CreateInstance("ClassName." + clsName);
            if (obj is ClassBase)
                (obj as ClassBase).Write();
        }
    }
}