λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ–₯️/C#

[C#] λ¦¬ν”Œλ ‰μ…˜(Reflection)

by HanaV 2023. 10. 10.
728x90
 
 

Reflection

 

λ¦¬ν”Œλ ‰μ…˜

 λ¦¬ν”Œλ ‰μ…˜(Reflection)은 'λ°˜μ‚¬'λΌλŠ” λœ»μ΄λ‹€. λ°˜μ‚¬λ˜λ©΄ μžμ‹ μ˜ λͺ¨μŠ΅μ΄ λ³΄μ΄λŠ” κ²ƒμ²˜λŸΌ, C#μ—μ„œ λ¦¬ν”Œλ ‰μ…˜μ€ 자기 μžμ‹ μ— λŒ€ν•œ 정보λ₯Ό λ°˜μ‚¬ν•˜λ“―μ΄ λ³΄λŠ” κΈ°λŠ₯을 λ§ν•œλ‹€.

 λ‹€μ‹œ μ •ν™•νžˆ μ •λ¦¬ν•˜μžλ©΄, λ¦¬ν”Œλ ‰μ…˜μ΄λž€ λŸ°νƒ€μž„ 쀑에 ν”„λ‘œκ·Έλž¨μ˜ 메타데이터λ₯Ό μ–»κ³  μˆ˜μ •ν•  수 μžˆλŠ” κΈ°λŠ₯이닀. κ°μ²΄μ˜ ν˜•μ‹ 이름, ν”„λ‘œνΌν‹°, λ©”μ„œλ“œ, ν•„λ“œ, 이벀트 λ“± κ·Έ 객체의 정보λ₯Ό λ“€μ—¬λ‹€λ³Ό 수 μžˆλ‹€.

λ©”νƒ€λ°μ΄ν„°λŠ” 데이터에 κ΄€ν•œ 데이터이닀. 즉, 데이터에 λŒ€ν•œ μ„€λͺ…, ꡬ쑰, 속성 λ˜λŠ” λ‹€λ₯Έ λ°μ΄ν„°μ˜ 정보λ₯Ό λ‹΄κ³  μžˆλŠ” 데이터λ₯Ό λ§ν•œλ‹€.

 

λ¦¬ν”Œλ ‰μ…˜μ΄ ν•„μš”ν•œ 이유

κ·Έλ ‡λ‹€λ©΄ λ¦¬ν”Œλ ‰μ…˜μ€ μ™œ ν•„μš”ν•œ κ²ƒμΌκΉŒ?

 λ¦¬ν”Œλ ‰μ…˜μ€ 주둜 λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό ν•  λ•Œ 많이 쓰인닀. μ½”λ“œμ˜ 각 뢀뢄이 μ˜¬λ°”λ₯΄κ²Œ μž‘λ™ν•˜λŠ”μ§€ 확인할 λ•Œ, μš°λ¦¬λŠ” κ·Έ λ©”μ„œλ“œμ— ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό λ„£μ–΄κ°€λ©° 확인을 ν•œλ‹€. λ©”μ„œλ“œ μˆ˜κ°€ 적닀면 무리 μ—†κ² μ§€λ§Œ, λ§Œμ•½ 수 백개λ₯Ό λ„˜μ–΄κ°„λ‹€λ©΄ ν•˜λ‚˜ν•˜λ‚˜ μˆ˜λ™μœΌλ‘œ ν•˜λŠ” 것은 맀우 λΉ„νš¨μœ¨μ μΌ 것이닀.
 λ¦¬ν”Œλ ‰μ…˜μ„ μ‚¬μš©ν•˜λ©΄, λ¦¬ν”Œλ ‰μ…˜μœΌλ‘œ ν…ŒμŠ€νŠΈ ν•  클래슀의 λ©”μ„œλ“œλ₯Ό λ™μ μœΌλ‘œ κ²€μ‚¬ν•œ ν›„, ν…ŒμŠ€νŠΈ λ©”μ„œλ“œλ₯Ό λ™μ μœΌλ‘œ μƒμ„±ν•˜κ²Œ ν•˜κ³  μ‹€ν–‰ν•˜λ©΄ 효율적으둜 λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό 진행할 수 μžˆλ‹€.

 λ˜ν•œ, μ™ΈλΆ€ 라이브러리λ₯Ό μ“°λŠ”λ°, κ·Έ λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ–΄λ–»κ²Œ κ΅¬μ„±λ˜μ–΄ μžˆλŠ”μ§€ 뢄석이 ν•„μš”ν•  λ•Œ λ¦¬ν”Œλ ‰μ…˜μœΌλ‘œ μ™ΈλΆ€ 라이브러리λ₯Ό 검사할 μˆ˜λ„ μžˆλ‹€.

 λ˜ λ‹€λ₯Έ κ°•λ ₯ν•œ κΈ°λŠ₯은 λ¦¬ν”Œλ ‰μ…˜μ„ μ‚¬μš©ν•΄μ„œ λ™μ μœΌλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•΄μ„œ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ‹€λŠ” 것이닀.
 λ™μ μœΌλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€λŠ” 것은 λŸ°νƒ€μž„μ—μ„œ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 것이고, μ •μ μœΌλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€λŠ” 것은 컴파일 μ‹œμ μ—μ„œ 이미 객체λ₯Ό μƒμ„±ν•˜κ³  ν• λ‹Ήν•˜λŠ” 것이닀. λ™μ μœΌλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 것은 ν”„λ‘œκ·Έλž¨μ΄ λŸ°νƒ€μž„ 상황에 따라 객체λ₯Ό μ‘°μž‘ν•˜κ±°λ‚˜ ν™•μž₯ν•˜λŠ” 데 μœ μ—°ν•˜κ²Œ ν™œμš©λ  수 μžˆλ‹€.

 

object 클래슀의 GetType()

 λͺ¨λ“  데이터 ν˜•μ‹μ€ Object ν˜•μ‹μ— ν¬ν•¨λ˜κΈ° λ•Œλ¬Έμ— GetType() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. GetType() λ©”μ„œλ“œλŠ” 객체의 ν˜•μ‹ 정보λ₯Ό λ°˜ν™˜ν•˜λŠ” 데 μ‚¬μš©λ˜λ©°, 객체의 ν˜•μ‹ 정보λ₯Ό λ¦¬ν”Œλ ‰μ…˜μ„ 톡해 μ ‘κ·Όν•  수 있게 ν•΄ μ€€λ‹€.

string a = "Hello, World!";
Type type = a.GetType();
Console.WriteLine(type.FullName);

Name은 String, FullName은 System.String λ“± κ°€μ Έμ˜¨ 객체의 ν˜•μ‹μ— λ‹€μ–‘ν•œ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄μ„œ 정보λ₯Ό λ³Ό 수 μžˆλ‹€.

 

typeof()도 λ¦¬ν”Œλ ‰μ…˜μΌκΉŒ?

 typeof() μ—°μ‚°μžλŠ” 컴파일 μ‹œμ μ—μ„œ ν˜•μ‹μ„ κ²€μ‚¬ν•˜κΈ° λ•Œλ¬Έμ— λ¦¬ν”Œλ ‰μ…˜μ€ μ•„λ‹ˆλ‹€. typeof μ—°μ‚°μžμ™€ GetType() λ©”μ„œλ“œμ˜ μ°¨μ΄λŠ” μ•„λž˜μ²˜λŸΌ typeofλŠ” ν˜•μ‹μ„ 직접 λ°›κ³ , GetType()은 μΈμŠ€ν„΄μŠ€μ— λŒ€ν•΄ ν˜ΈμΆœλœλ‹€λŠ” 것이닀.

Type intType = typeof(int);
Type stringType = text.GetType();

 λ§Œμ•½ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•Šκ³  GetType()으둜 string ν˜•μ‹μ„ λ°”λ‘œ λ°›μ•„μ˜€κ³  μ‹ΆμœΌλ©΄, μ•„λž˜μ™€ 같이 ν˜•μ‹μ˜ 이름을 λ„£μ–΄μ£Όλ©΄ λœλ‹€.

Type stringType = Type.GetType("System.String");

 

 λ‹€μ‹œ λŒμ•„κ°€μ„œ type에 μžˆλŠ” λ©”μ„œλ“œλ“€μ„ λ‹€μ‹œ μ‚΄νŽ΄λ³΄λ©΄, 정말 λ§Žμ€ 메타데이터λ₯Ό 뽑아낼 수 μžˆλŠ” 것을 μ•Œ 수 μžˆλ‹€. 이 λͺ¨λ“  κ²ƒμ˜ μ‚¬μš©λ²•μ„ μ™ΈμšΈ μˆ˜λŠ” μ—†μ§€λ§Œ, μ‚¬μš©λ²•μ€ 거의 λ‹€ λΉ„μŠ·ν•˜κΈ° λ•Œλ¬Έμ— λͺ‡ 개만 μ˜ˆμ‹œλ‘œ 보도둝 ν•˜μž.

μ•„λž˜λŠ” 각각 μΈν„°νŽ˜μ΄μŠ€, ν•„λ“œ, λ©”μ„œλ“œ, ν”„λ‘œνΌν‹°λ₯Ό λ½‘μ•„λ‚΄λŠ” λ©”μ„œλ“œμ΄λ‹€.

GetInterfaces() (return: Type[])

static void PrintInterfaces(Type type)
{
    Type[] interfaces = type.GetInterfaces();
    foreach (Type i in interfaces) {
        Console.WriteLine($"Name: {i.Name}");
    }
}

GetFields() (return: FieldInfo[])

static void PrintFields(Type type)
{
    FieldInfo[] fields = type.GetFields(
        BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); // 이 뢀뢄을 μ‘°μ •ν•˜μ—¬ 검색 μ˜΅μ…˜μ„ 지정할 μˆ˜λ„ μžˆλ‹€
    foreach (FieldInfo f in fields) {
        string accessLevel = "protected";
        if (f.IsPublic) {
            accessLevel = "Public";
        }
        else if (f.IsPrivate) {
            accessLevel = "Private";
        }
        Console.WriteLine($"Access: {accessLevel}, Type: {f.FieldType.Name}, Name: {f.Name}");
    }
}

GetMethods() (return: MethodInfo[])

static void PrintMethods(Type type)
{
    MethodInfo[] methods = type.GetMethods();
    foreach (MethodInfo m in methods) {
        Console.Write($"ReturnType: {m.ReturnType.Name}, Name: {m.Name}, Parameter: ");

        ParameterInfo[] parameters = m.GetParameters();
        for (int i = 0; i < parameters.Length; i++) {
            Console.Write(parameters[i].ParameterType.Name);
            if (i < parameters.Length - 1) {
                Console.Write(", ");
            }
        }
        Console.WriteLine();
    }
}

GetProperties() (return: PropertyInfo[])

static void PrintProperties(Type type)
{
    PropertyInfo[] properties = type.GetProperties();
    foreach (PropertyInfo p in properties) {
        Console.WriteLine($"Type: {p.PropertyType.Name}, Name: {p.Name}");
    }
}

λ¨Όμ € int에 λŒ€ν•œ ν˜•μ‹ 정보λ₯Ό λ½‘μ•„λ‚΄λ³΄μž.

int a = 0;
Type type = a.GetType();

PrintInterfaces(type);
PrintFields(type);
PrintMethods(type);
PrintProperties(type);
Int32
----- Interfaces -----
Name: IComparable
Name: IConvertible
Name: ISpanFormattable
Name: IFormattable
Name: IComparable`1
Name: IEquatable`1
Name: IBinaryInteger`1
Name: IBinaryNumber`1
Name: IBitwiseOperators`3
Name: INumber`1
Name: IAdditionOperators`3
Name: IAdditiveIdentity`2
Name: IComparisonOperators`2
Name: IEqualityOperators`2
Name: IDecrementOperators`1
Name: IDivisionOperators`3
Name: IIncrementOperators`1
Name: IModulusOperators`3
Name: IMultiplicativeIdentity`2
Name: IMultiplyOperators`3
Name: ISpanParseable`1
Name: IParseable`1
Name: ISubtractionOperators`3
Name: IUnaryNegationOperators`2
Name: IUnaryPlusOperators`2
Name: IShiftOperators`2
Name: IMinMaxValue`1
Name: ISignedNumber`1
----- Fields -----
Access: Private, Type: Int32, Name: m_value
Access: Public, Type: Int32, Name: MaxValue
Access: Public, Type: Int32, Name: MinValue
----- Methods -----
ReturnType: Int32, Name: CompareTo, Parameter: Object
ReturnType: Int32, Name: CompareTo, Parameter: Int32
ReturnType: Boolean, Name: Equals, Parameter: Object
ReturnType: Boolean, Name: Equals, Parameter: Int32
ReturnType: Int32, Name: GetHashCode, Parameter:
ReturnType: String, Name: ToString, Parameter:
ReturnType: String, Name: ToString, Parameter: String
ReturnType: String, Name: ToString, Parameter: IFormatProvider
ReturnType: String, Name: ToString, Parameter: String, IFormatProvider
ReturnType: Boolean, Name: TryFormat, Parameter: Span`1, Int32&, ReadOnlySpan`1, IFormatProvider
ReturnType: Int32, Name: Parse, Parameter: String
ReturnType: Int32, Name: Parse, Parameter: String, NumberStyles
ReturnType: Int32, Name: Parse, Parameter: String, IFormatProvider
ReturnType: Int32, Name: Parse, Parameter: String, NumberStyles, IFormatProvider
ReturnType: Int32, Name: Parse, Parameter: ReadOnlySpan`1, NumberStyles, IFormatProvider
ReturnType: Boolean, Name: TryParse, Parameter: String, Int32&
ReturnType: Boolean, Name: TryParse, Parameter: ReadOnlySpan`1, Int32&
ReturnType: Boolean, Name: TryParse, Parameter: String, NumberStyles, IFormatProvider, Int32&
ReturnType: Boolean, Name: TryParse, Parameter: ReadOnlySpan`1, NumberStyles, IFormatProvider, Int32&
ReturnType: TypeCode, Name: GetTypeCode, Parameter:
ReturnType: Type, Name: GetType, Parameter:
----- Properties -----

μ΄λ ‡κ²Œ Int32에 μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€, ν•„λ“œ, λ©”μ„œλ“œμ— λŒ€ν•œ 정보듀이 μ­‰ λ‚˜μ˜€κ²Œ λœλ‹€.

μ΄λ²ˆμ—” 직접 classλ₯Ό λ§Œλ“€μ–΄ κ·Έ 객체에 λŒ€ν•œ 정보λ₯Ό λ½‘μ•„λ³΄μž

class Inventory
{
    public string? Product { get; set; }
    public int Count { get; set; }
}
Inventory inventory = new Inventory();
Type type2 = inventory.GetType();
Console.WriteLine(type2.Name); // Inventory

PrintInterfaces(type2);
PrintFields(type2);
PrintMethods(type2);
PrintProperties(type2);
Inventory
----- Interfaces -----
----- Fields -----
Access: Private, Type: String, Name: <Product>k__BackingField
Access: Private, Type: Int32, Name: <Count>k__BackingField
----- Methods -----
ReturnType: String, Name: get_Product, Parameter:
ReturnType: Void, Name: set_Product, Parameter: String
ReturnType: Int32, Name: get_Count, Parameter:
ReturnType: Void, Name: set_Count, Parameter: Int32
ReturnType: Type, Name: GetType, Parameter:
ReturnType: String, Name: ToString, Parameter:
ReturnType: Boolean, Name: Equals, Parameter: Object
ReturnType: Int32, Name: GetHashCode, Parameter:
----- Properties -----
Type: String, Name: Product
Type: Int32, Name: Count

μ΄λ ‡κ²Œ λ§Œλ“  ν•„λ“œλ“€κ³Ό get set λ©”μ„œλ“œ, 그리고 ν”„λ‘œνΌν‹°κΉŒμ§€ λͺ¨λ‘ μ•Œμ•„λ‚Ό 수 μžˆλ‹€.

 

SetValue()

값을 Getν•΄μ˜¬ 수 μžˆλ‹€λ©΄, Setν• μˆ˜λ„ μžˆλ‹€.
μ•„κΉŒ μ“΄ GetProperty() λ©”μ„œλ“œλ‘œ ν”„λ‘œνΌν‹°λ₯Ό κ°€μ Έμ™€μ„œ SetValue() λ©”μ„œλ“œλ‘œ 값을 μ„€μ •ν•˜λ©΄ λœλ‹€.

PropertyInfo productProperty = typeof(Inventory).GetProperty("Product");
PropertyInfo countProperty = typeof(Inventory).GetProperty("Count");
productProperty.SetValue(inventory, "Example Product");
countProperty.SetValue(inventory, 10);

 

 

 

전체 μ½”λ“œλŠ” Github에 μ˜¬λ €λ†¨μŠ΅λ‹ˆλ‹€

728x90

"); wcs_do();