본문 바로가기
C#/C# 학습 (TIL)

C# 인덱서, 제네릭, 확장메서드

by jjiing 2022. 7. 1.

▶인덱서란?

C++의 인덱스 연산자 오버로딩과 같이 객체의 인덱스 연산을 시킬 때 특정함수를 호출해주는 메커니즘을 의미한다.

즉, 객체를 배열처럼 사용하는 것이 가능하다.
- 가독성 + 중복 로직 방지

▷ C# 인덱서의 특징

-C# 언어의 인덱서는 this 키워드인덱스 연산자 ( [] )를 조합해서 정의하는 것이 가능하다.
-C#언어의 인덱서는 this 키워드를 통해서 정의되기 때문에 정적 클래스는 인덱서를 정의하는 것이 불가능하다.
-C# 언어의 인덱서는 프로퍼티와 마찬가지로 get과 set을 통해서 로직을 정의하는 것이 가능하다.
-C# 언어의 인덱서는 메서드와 마찬가지로 virtual 과 override 키워드의 조합으로 오버라이드 매커니즘을 구현하는 것이 가능하다.

 

awake 외부의 클래스
awake문 내부
결과

 

 

 


▶제네릭이란?


C++의 템플릿과 마찬가지로 클래스 또는 메서드를 정의할 때 타입을 지정하지 않고 구현할 수 있는 매커니즘을 의미한다.

▷ 제네릭의 특징

- C#언어의 제네릭은 <T>와 같은 제네릭 타입을 명시함으로써 정의하는 것이 가능하다.
(ex) Class CWidget<T>

- C# 언어의 제네릭은 기본적으로 모든 데이터 타입에 동작하도록 설계되어야 한다.
- 제네릭 클래스 또는 메서드에 어떤 데이터 타입이 지정되어도 내부 로직에 변화가 발생하면 안된다.
 (설계를 할 때 컴파일 오류(빨간줄) /논리오류 를 고려해야한다.)



▷ C# 언어 제네릭의 데이터 타입 제한

- class CWidget<T> where T : class          (타입을 참조 형식으로 제한)
- class CWidget<T> where T : struct         (타입을 값 형식으로 제한)
- class CWidget<T> where T : SomeClass      (타입을 SomeClass를 직/ 간접적으로 상속하는 형식으로 제한)
- class CWidget<T> where T : SomeInterface  (타입을 SomeInterface 직/ 간접적으로 따르는 형식으로 제한)
- class CWidget<T, U> where T : U      (타입을 U(클래스 or 인터페이스)를 직/간접적으로 상속하는 형식으로 제한)

 

 

위의 인덱서 예시를  제네릭화했을 때.

awake문 외부

 

awake 문 내부
결과

 

 

 

 

 

 



 ▷ is 와 as 연산자를 통한 데이터 형변환

is 연산자 : 결과 값이 참/ 거짓으로 판정되며 값 형식과 참조 형식 데이터에 모두 사용하는 것이 가능하다.
as 연산자 : 결과를 해당 데이터 형의 참조 값으로 반환시키기 때문에 참조 형식의 데이터 타입에만 사용하는 것이 가능하다.



(ex)
is 연산자

object oIntObject = 10;
if(oIntObject is int)

    // 
}


as 연산자

object oClassObject = new someClass();
var SomeClass = oClassObject as SomeClass;
if(oSomeClass !=null)
{
    //
}

 

 

 

 

▶확장메서드란?


 기존에 제공되는 클래스 또는 외부 라이브러리에 속해있는 클래스에
새로운 기능을 
"상속"이 아닌 메서드를 이용해서 기능을 확장하는 것을 의미

 

 


▷확장메서드의 특징
- c#언어의 확장 메서드는 정적 클래스만을 통해서 정의하는 것이 가능하다.
즉, 정적 클래스가 아니면 확장 메서드 자체를 구현하는 것이 불가능하다.

- c#언어의 확장 메서드를 정의하는 정적 클래스는 반드시 최상단 영역에 위치 시켜야한다.

- 특정 클래스의 중첩 클래스로는 확장 메서드를 정의하는 것이 불가능

 

(참고)
- 참고로 C#은 상속 하나만 가능. (다중상속 x ) + 확장메서드 + 인터페이스

- 확장 메서드에는 함수의 집합 또는 메서드의 집합이 들어가는게 베스트

- 코드의 간결화, 불필요한 로직제거, 중복 로직 제거

 

 

 

 

확장메서드 예시) 

 

static class CArrayExtends
{
    //! 값을 교환한다.
    public static void Swap(this int[] a_oSender, int a_nLhs, int a_nRhs)
    {
        int nTemp = a_oSender[a_nLhs];
        a_oSender[a_nLhs] = a_oSender[a_nRhs];
        a_oSender[a_nRhs] = nTemp;
    }

    //!문자열을 반환한다.
    public static string GetString(this int[] a_oSender)
    {
        var oStringBuilder = new System.Text.StringBuilder();

        for(int i=0;i<a_oSender.Length;i++)
        {
            oStringBuilder.AppendFormat("{0}, ", a_oSender[i]);
        }
        return oStringBuilder.ToString();
    }

    //!합계를 계산한다.
    public static int GetSumValue(this int[] a_oSender , int a_nDefaultValue = 0)
    {
        int nSumValue = a_nDefaultValue;
        for(int i =0;i<a_oSender.Length; i++)
        {
            nSumValue += a_oSender[i];
        }
        Debug.Log("GetSumValue 호출");
        return nSumValue;
    }


    //!합계를 계산한다. - 제네릭 버전 
    //Example_03.CArrayList는 위의 제네릭 예시 확장메서드. (Example_03은 스크립트네임)
    public static object GetSumValue<T> (this Example_03.CArrayList<T> a_nSender) where T : struct
    {
        //제네릭 타입을 통해서 메서드 or 함수를 만들 때는 반드시 예외를 걸어줘야한다.(조건문 등으로)

        object oSumValue = 0;

        for(int i=0;i<5;i++)
        {
            int nValue = 0;
            string oString = a_nSender[i].ToString();


            if(int.TryParse(oString, out nValue))    //예외처리
            {
                oSumValue = (int)oSumValue + nValue;
            }

        }

        return oSumValue;
    }

    //!평균을 계산한다.

    public static float GetAverageValue(this int[] a_oSender)
    {
        Debug.Log("GetAverageValue 호출");
        return GetSumValue(a_oSender) / (float)a_oSender.Length;    //(float) : 혹시 모를 데이터 손실을 위해

    }

}

 

 

외부 클래스에서 이 확장메서드를 참고하는 경우

 

 

 

 

 

(참고)

캐스팅(형변환) 연산자
C : (Type) =강제형변환 (좋은 방식은 아님, 오류 발생 가능성 높음) 
C++
C# : 대표적인 형변환 3총사(Convert, Parse, TryParse)


<C# 캐스팅 연산자>


Convert
- '기본' 데이터 형식을 다른 '기본' 데이터 형식으로 변환
(기본데이터 형식 : int, byte, char, bool 등..)
parse 
- 문자열을 해당하는 형식으로 변환시킨다.
TryParse
- 문자열을 해당하는 형식으로 변환시키면 성공 여부 T/F
-체크해야할 String 값이 숫자인 경우
 : int 타입으로 컨버팅해서 반환
-체크해야할 String 값이 숫자가 아닌 경우
: 설정한 기본값으로 변환