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 |