본문 바로가기
2학년 2학기/윈도우즈 프로그래밍

고급 프로그래밍 기법(1) - 제너릭, Attribute

by kkkkk1023 2024. 9. 30.

1. 제네릭(Generic)

제네릭 프로그래밍은 클래스나 메소드에서 특정 데이터형에 의존하지 않고, 다양한 자료형을 처리할 수 있도록 프로그래밍하는 기법입니다. 이를 통해 코드 재사용성을 높이고, 자료형에 따른 중복 코드를 줄일 수 있습니다.

제네릭의 주요 특징:

  • 타입 매개변수: 제네릭 클래스나 메소드에서 사용할 자료형을 미리 정해놓지 않고, 필요한 시점에 구체적인 자료형을 지정할 수 있습니다. 타입 매개변수는 <T> 형태로 사용됩니다.
  • 장점: 다양한 자료형을 처리할 수 있어 재사용성이 높아지고, 자료형에 따른 중복 코드를 줄일 수 있습니다.

 

제네릭 클래스 예시:

class SimpleGeneric<T> {
    private T[] values;
    private int index;

    public SimpleGeneric(int len) {
        values = new T[len];
        index = 0;
    }

    public void Add(params T[] args) {
        foreach (T e in args) {
            values[index++] = e;
        }
    }

    public void Print() {
        foreach (T e in values) {
            Console.Write(e + " ");
        }
        Console.WriteLine();
    }
}

 

 

제네릭 클래스 사용 예시:

public class GenericClassExample {
    public static void Main() {
        SimpleGeneric<int> gInteger = new SimpleGeneric<int>(10);
        SimpleGeneric<double> gDouble = new SimpleGeneric<double>(10);

        gInteger.Add(1, 2, 3);
        gInteger.Print();

        gDouble.Add(10.5, 20.5, 30.5);
        gDouble.Print();
    }
}

 

 

 

2. 제네릭 인터페이스

 

제네릭 인터페이스는 타입 매개변수를 사용하는 인터페이스로, 다양한 자료형에 대해 인터페이스를 정의할 수 있습니다. 이를 통해 인터페이스를 구현하는 클래스에서 자료형을 지정하여 유연한 설계가 가능합니다.

 

제네릭 인터페이스 구현 예시:

interface IGenericInterface<T> {
    void SetValue(T x);
    string GetValueType();
}

class GenericClass<T> : IGenericInterface<T> {
    private T value;

    public void SetValue(T x) {
        value = x;
    }

    public string GetValueType() {
        return value.GetType().ToString();
    }
}

 

제네릭 인터페이스 사용 예시:

public class GenericInterfaceApp {
    public static void Main() {
        GenericClass<int> gInteger = new GenericClass<int>();
        GenericClass<string> gString = new GenericClass<string>();

        gInteger.SetValue(10);
        gString.SetValue("Text");

        Console.WriteLine(gInteger.GetValueType());
        Console.WriteLine(gString.GetValueType());
    }
}

 

 

 

3. 제네릭 메소드

 

제네릭 메소드타입 매개변수를 사용하는 메소드로, 특정 자료형에 구애받지 않고 여러 자료형을 처리할 수 있습니다. 제네릭 메소드를 통해 동일한 로직을 자료형에 맞게 유연하게 처리할 수 있습니다.

제네릭 메소드 예시:

void Swap<T>(ref T x, ref T y) {
    T temp = x;
    x = y;
    y = temp;
}

public static void Main() {
    int a = 1, b = 2;
    double c = 1.5, d = 2.5;

    Swap(ref a, ref b);
    Swap(ref c, ref d);

    Console.WriteLine($"After swap: a = {a}, b = {b}");
    Console.WriteLine($"After swap: c = {c}, d = {d}");
}

 

 

 

4. 타입 매개변수의 제한

 

타입 매개변수를 사용할 때, 특정 조건을 부여하여 매개변수가 어떤 자료형을 따르도록 제한할 수 있습니다. C#에서는 where 키워드를 사용하여 이러한 제한을 설정합니다.

타입 매개변수 제한 예시:

// 'where T : SystemException'은 제약 조건을 설정하는 부분으로, 
// 이 제네릭 클래스에서 T 타입은 반드시 **SystemException**을 상속한 타입이어야 한다는 것을 의미합니다. 
// 즉, 이 클래스는 SystemException 및 그 하위 클래스들만 사용할 수 있습니다.


class GenericType<T> where T : SystemException {
    private T value;

    public GenericType(T v) {
        value = v;
    }

    public override string ToString() {
        return "Type is " + value.GetType();
    }
}

public static void Main() {
    GenericType<NullReferenceException> gNullEx = new GenericType<NullReferenceException>(new NullReferenceException());
    Console.WriteLine(gNullEx.ToString());
}

 

 

 

5. 애트리뷰트(Attribute)

 

애트리뷰트는 클래스, 메소드, 필드 등에 추가적인 메타데이터(정보)를 제공하는 기능입니다. .NET에서 제공하는 표준 애트리뷰트를 사용하거나, 사용자 정의 애트리뷰트를 만들어 특정 동작을 정의할 수 있습니다.

표준 애트리뷰트 - Obsolete:

class ObsoleteAttrApp {
    [Obsolete("This method is obsolete.")]
    public static void OldMethod() {
        Console.WriteLine("Old method");
    }

    public static void Main() {
        OldMethod();  // 경고 메시지가 출력됨
    }
}

 

 

 

6. 사용자 정의 애트리뷰트

 

사용자 정의 애트리뷰트System.Attribute 클래스를 상속하여 새로운 애트리뷰트를 만들 수 있습니다.

사용자 정의 애트리뷰트 예시:

public class MyAttrAttribute : Attribute {
    private string message;

    public MyAttrAttribute(string message) {
        this.message = message;
    }

    public string Message {
        get { return message; }
    }
}

[MyAttr("This is a custom attribute.")]
class MyAttributeApp {
    public static void Main() {
        Type type = typeof(MyAttributeApp);
        object[] attrs = type.GetCustomAttributes(false);

        foreach (MyAttrAttribute attr in attrs) {
            Console.WriteLine(attr.Message);
        }
    }
}