TIL

2024 11 11 TIL

noc777 2024. 11. 11. 22:48

JSON 을 이용해 서버의 API를 가져오는 방법의 특강을 듣다 제너릭과 익명메서드에 대한 이해가 부족하였음을 느끼고 질문을 하게되었습니다.  C# 주차 때 개념을 이해하기 어려워 놓친 부분이 많다는 것을 다시 한번 인식하고 생각을 정리해보는 시간을 가져봅니다.

 

제너릭에 관해서 

 

기존에는 꺽쇠(<>)안에 자료형을 넣은 형태로만 생각하고 있었기에 리스트와 같은 자료구조에 쓰이는 개념정도로만 생각하였습니다.

그래서 특강에서 보았던 제너릭 방식에 대해서 제가 T로 선언하고 호출하는 곳에서 자료형을 사용한 방식을 제대로 이해를 못했던 것 같습니다.

//내가 생각했던 개념

List<string>  <- 여기 꺽쇠에 들어가는 자료형 방식

 

일단 먼저 제너릭을 사용하였던 이유 

 

특강에서 제너릭을 사용하였던 이유는 SavePlayerData, SaveInvenData 등 Json을 저장하는 메서드를 따로 구분하여 만들다보니

저장할 데이터가 많아질수록 메서드의 수가 계속 늘어나는 것에서 리팩토링을 하는 과정에 사용되었습니다.

//제너릭을 사용하기 전 (SaveInvenData라는 메서드도 따로 선언되어 있음)
public void SavePlayerData(string json)
{
	//직렬화 코드는 호출하는 쪽에서 구현이 되어있음
    File.WriteAllText(Application.persistentDataPath + "/PlayerData.txt",json);
}


//제너릭을 사용한 후 (비슷한 기능을 가진 두 메서드가 매개변수를 통해 실기능이 분리되어 작동함)
public void SaveData<T>(T data)
{
	string json = JsonUtility.ToJson(data);
    File.WriteAllText(Application.persistentDataPath + $"/{typeof(T).ToString()}.txt",json);
}
질문을 통해 이해한 것

 

특강을 마치고나서 정확한 이해를 위해 튜터님께 질문하는 시간을 가지게 되었습니다. 

이에 제가 이해한 바를 정리하여 봅니다. 

 

클래스나 메서드 뒤에<T> 를 붙여 사용합니다.  T(Type)를 사용한 메서드를 다른 곳에서 불러와 사용한다면 불러온 곳에서 T의 자료형을

정해줄 수 있습니다.    (이런 부분은 약간 필드의 var 키워드와 유사한 느낌이 있습니다.)

강의에서 이런 방식으로 직렬화하여 저장할 때 받아오는 클래스 타입을 구분없이 매개변수로 받고 경로를 다르게 저장하였습니다.

//T를 사용한 스크립트
public void Save<T> (T data) //매개변수가 T로 어느것이든 받아온다.
{
    string json = JsonUtility.ToJson(data) //받아온 클래스를 직렬화시키는 코드
}




//제너릭 메서드를 호출한 스크립트

[Serializable]
public class PlayerData  //직렬화 시킬 클래스 PlayerData
{
    string name;
    int level;
}

[Serializable]
public class InvenData  //직렬화 시킬 클래스 InvenData
{
    //Slot 관련 데이터
}

public class Player : monobehavior
{
    PlayerData playerData; 
    InvenData invenData;
    
    public void SaveData()
    {
        DataManager.instance.Save(playerData); //매개변수가 T인 메서드에 PlayerData타입 클래스를 넣어준 모습
        DataManager.instance.Save(invenData); //위와 같이 같은 메서드에 InvenData 타입 클래스를 넣어준 모습
    }
}

 

추가로 클래스에서 제네릭을 사용할 때 where 을 붙이기도 하는데 이것은 제약 조건이라고 하는 것 같습니다.

해당 클래스를 상속받을 수 있는 조건으로 추측합니다.

제네릭 싱글톤도 같은 개념으로 보이는 데 이것은 추가적으로 질문이 필요할 것 같습니다.

public class MyClass<T> where T : struct //T 는 값 형식이어야 한다.

public class MyClass<T> where T : class  //T 는 참조 형식이어야 한다.

public class MyClass<T> where T : new()  //T 는 매개 변수가 없는 생성자가 있어야만 한다.

public class MyClass<T> where T : 부모 클래스의 이름 //T 는 명시한 부모 클래스의 자식 클래스여야 한다.

public class MyClass<T> where T : 인터페이스 이름 //T 는 명시한 인터페이스를 반드시 구현해야한다.

public class MyClass<T> where T : U //T는 매개 변수 U로 부터 상속받은 클래스여야 한다.

 

 

익명메서드에 관해 

 

특강에서는 익명메서드를 활용해서 간단한 식을 처리하였습니다. 

 

익명메서드를 사용하는 이유는 간단한 구조의 메서드를 일반 메서드를 사용하여 출력하였을 때 추가로 구현하는 대신 

메서드안에서 익명 메서드를 사용하여 대체가 가능하기 때문입니다.

//일반 메서드
void Test()
{
   Debug.Log("테스트");
}

//간단한 구조의 일반 메서드 사용

private void TestBoard()
{
    Test();
    Test2(); //익명 메서드를 사용하지 않으면 또 다른 간단한 구조의 메서드를 만들 때도 일반 메서드를 추가 구현해야함
}

//또다른 간단한 구조의 메서드
void Test2()
{
   Debug.Log("테스트2");
}

 

버튼에 이벤트를 이벤트를 구독할 때 익명메서드와 람다를 사용한 예제

//익명메서드 구조  (일회성 메서드) 
delegate(매개변수){식};

//익명메서드 사용 예제
public void TestBoard()
{
    btn.onClick.AddListener(delegate () {Debug.Log("Test2"); }); //버튼에 할당하는 익명메서드
}

//delegate 대신 => 을 사용
(매개변수) => {식};

//람다식 사용 예제
public void TestBoard()
{
     btn.onClick.AddListener(() => {Debug.Log("Test2"); }); //람다식 사용
}

 

자료로 정리해보려면 좀 더 자세히 알아보아야 하기에 과제 중 많은 시도가 필요해보입니다.

'TIL' 카테고리의 다른 글

2024 11 13 TIL  (0) 2024.11.13
2024 11 12 TIL  (0) 2024.11.12
2024 11 08 TIL  (0) 2024.11.08
2024 11 07 TIL  (0) 2024.11.07
2024 11 06 TIL  (1) 2024.11.06