코드실행 자동화

  • 기존에 알고리즘을 실행하기 위해서는 Program.cs의 Main 함수를 실행하는 방식
  • 해당 Solution을 실행 하기 위해서는 Main 안에서 Class.solution을 실행 해야하는 귀찮음
  • 별도의 Code 수정 없이 실행 버튼을 누르면 자동으로 실행되는 로직을 구상

Program.cs

using System.Reflection;

public abstract class KataBase
{
    public abstract void Example();
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine("실행하고자 하는 문제의 Class Name을 적어주세요:");
        string problemClassName = Console.ReadLine();

        var testType = Assembly.GetExecutingAssembly().GetTypes()
            .FirstOrDefault(t => t.IsSubclassOf(typeof(KataBase)) && t.Name == problemClassName);

        if (testType != null)
        {
            var instance = Activator.CreateInstance(testType) as KataBase;
            instance?.Example(); 
        }
        else
        {
            Console.WriteLine($"Problem class '{problemClassName}' not found.");
        }
    }
}
  • 먼저 Reflection에 대해서 알아야 합니다.

    Reflection

  • Reflection은 프로그램 자체 구조와 동작을 검사하고 조작할 수 있게 해주는 기능
  • Assembly, Module 및 Type에 대한 정보뿐만 아니라 Type의 인스턴스를 동적생성하며
  • 메서드에 바인딩, Field, Attribute에 엑세스 하는 기능을 포함합니다.

Inspecting Type Information (유형 정보 검사)

Type Class

  • System.Type 은 Reflection의 핵심
  • 클래스, 인터페이스, 배열, 값, 열거형, 파라매터, 제네릭, 퍼블릭, 프라이빗 생성 제네릭 유형 등 을 나타냄

Type 정보 가져오기

  • GetType()메서드를 이용해서 객체의 Type인스턴스를 가져오거나, typeof 키워드를 사용하여 Type의 인스턴스를 가져올 수 있습니다.
  • Type Instance를 가져오면, 메서드, 속성, 필드 이벤트등 다양한 측면을 검사할 수 있습니다.

Dynamic Instance Creation (동적 인스턴스 생성)

인스턴스 생성

  • ReflectionCompile 시 정확한 유형을 알지 못해도 RunTime에 인스턴스를 생성하는 기능을 제공
  • Acivator.CreateIntance는 해당 목적으로 사용되는 방법
  • 플러그인 아키텍쳐와 같은 Scenario, Compile Time에 알 수 없는 유형을 처리할 때 유용함
  • Type의 이름만 알고 있을 때 유용

Members Invocation and Access (맴버 호출 및 접근)

Member Access

  • Type객체가 있으면, GetMethod, GetProperty, GetField, GetEvent등을 이용하여 Type Member에 접근 할 수 있습니다.
  • 이후 속성값에 대한 설정 및 메서드를 호출하는 등 조작이 가능해집니다.

Binding Flag

  • Reflection Method에서는 일반적으로 BindingFlagsoverlode허용하며, 이것은 MemberType이 수행되는 방식을 제어합니다.

Assembly(어셈블리)

Assembly Class

  • Assembly Class를 사용하면, Load 하고 조작할 수 있습니다.

Performance Considerations

  • Reflection의 경우 동적 특성으로 인해서 직접 코드 실행에 비래 속도가 늦을 수 있습니다.
  • 성능이 중요한 경우 사용을 지양합니다.

코드에서의 Reflection 사용

using System.Reflection;

public static void Main()
{
	// 실행중인 Assembly중에서 KataBase의 클래스 중 입력한 ClassName과 동일한 타입을 찾습니다.
	var testType = Assembly
	.GetExecutingAssembly()
	.GetTypes()
	.FirstOrDefault(t => t.IsSubclassOf(typeof(KataBase)) 
	&& t.Name == problemClassName); 
}

Example Code

public class PairNumber : KataBase  
{                                                                                                                                
public string solution(string X, string Y)  
    {        
	    // 기본 반환값을 설정합니다. 이 값은 공통된 숫자가 없을 경우 반환됩니다.  
        string answer = "-1";  
  
        // X의 각 문자에 대한 카운트를 계산합니다.  
        var xCharCounts = X.GroupBy(c => c).ToDictionary(g => g.Key, g => g.Count());  
        // Y의 각 문자에 대한 카운트를 계산합니다.  
        var yCharCounts = Y.GroupBy(c => c).ToDictionary(g => g.Key, g => g.Count());  
  
        // 두 문자열에서 공통으로 나타나는 문자를 저장할 리스트를 생성합니다.  
        var commonChars = new List<char>();  
  
        // X에 있는 모든 문자를 반복하여 확인합니다.  
        foreach (var xChar in xCharCounts)  
        {            
	        // Y에도 같은 문자가 있는지 확인하고, 그렇지 않으면 계속합니다.  
            if (!yCharCounts.TryGetValue(xChar.Key, out int yCount)) continue;  
            // X와 Y에서의 해당 문자의 최소 등장 횟수를 찾습니다.  
            int minCount = Math.Min(xChar.Value, yCount);  
            // 공통 문자를 최소 등장 횟수만큼 리스트에 추가합니다.  
            commonChars.AddRange(Enumerable.Repeat(xChar.Key, minCount));  
        }  
        // 공통 문자가 없는 경우, 기본 반환값을 반환합니다.  
        if (!commonChars.Any()) return answer;  
  
        // 공통 문자를 내림차순으로 정렬합니다.  
        var sortedCommonChars = commonChars.OrderByDescending(c => c).ToArray();  
        // 만약 모든 공통 문자가 '0'이라면, 단일 '0'을 반환합니다.  
        return sortedCommonChars.All(c => c == '0') ? "0" : new string(sortedCommonChars);  
    }
}

public override void Example()  
{  
    string x = "100";  
    string y = "203045";  
    var result = solution(x,y);  
    Console.WriteLine($"결괏값 : {result}"); 
}

프로그램 실행

  • Example 메서드에 예제 입력
  • 실행 하려는 Class 실행 (여기서는 “PairNumber”)
  • 결괏값 확인

마치며

별 것 아닌 프로그램 이지만, Reflection에 대해 알 수 있었고, 불편한 것은 편하게 만드는 것이 개발자로서 할 일이라고 생각합니다.