✌️개요
Http통신 시 바디 입력이나, 로컬 저장 데이터를 만들 때 정말 잘 사용하고있는 `Newtonsoft.Json` 패키지
전에는 몰랐는데 유니티 패키지 매니져에서도 `com.unity.nuget.newtonsoft-json`을 입력하면 설치할 수 있다
아무튼
클래스 하나를 통째로 json 직렬화 시킬 일이 없어서 몰랐었는데
유니티의 API인 `JsonUtility.ToJson()`처럼 클래스를 통째로 Json화 시킬 때 사용하는 Newtonsoft.Json패키지의 `Jobject.FromObject()`가 여러가지 이점이 많다는걸 알게됐다
유니티의 API대비 좋은점을 기록한다
🔥본문
1. [JsonIgnore] 어트리뷰트
유니티의 `JsonUtility.ToJson()`은 에디터 내부의 직렬화와 동일하게 작동하기 때문에
`[SerializeField]`어트리뷰트를 쓴 `private`변수나 `public`변수같이 인스펙터에 보이게 직렬화된 변수들은 무조건 Json직렬화에 포함된다
이게 안좋은점은
예를 들어 데이터 클래스를 통째로 Json직렬화 시켜서 서버에 보낼 요청에 바디에 쓸려고 한다
근데 서버에서 규정한 입력값외에 게임에서만 필요한 변수들도 있을 때 그것만 Json직렬화에 제외할 수 없다는 것이다
하지만 `Newtonsoft.Json`패키지는 가능하다
일단 아래와같은 데이터 클래스가 있다고 치자
using Newtonsoft.Json;
...생략
[Serializable]
public class LocalSaveData
{
[SerializeField]
private int someInt;
[SerializeField]
private float someFloat;
[SerializeField]
private string someString;
[SerializeField]
private int[] someIntArr;
[SerializeField]
private List<int> someIntList;
[JsonIgnore]
public int ignoredInt;
public TestDataClass testDataClass;
#region 프로퍼티
[JsonIgnore]
public int SomeInt { get => someInt; set => someInt = value; }
public float SomeFloat { get => someFloat; set => someFloat = value; }
public string SomeString { get => someString; set => someString = value; }
public int[] SomeIntArr { get => someIntArr; set => someIntArr = value; }
public List<int> SomeIntList { get => someIntList; set => someIntList = value; }
#endregion
}
여기서 `ignoredInt`변수와 `SomeInt`프로퍼티에 `[JsonIgnore]`어트리뷰트를 붙였다
데이터는 아래 스샷과 같이 집어넣었다
그리고 Json 직렬화를 시켜보면 아래와같이 직렬화에 제외된다
public void JobjectTest()
{
Debug.Log(JObject.FromObject(localSave).ToString());
}
- 출력: `SomeInt`프로퍼티와 `ignoredInt`변수가 없다
{
"testDataClass": {
"testString": "This is TestDataClass",
"testIntList": [
7,
8,
9
]
},
"SomeFloat": 0.0,
"SomeString": "qwe",
"SomeIntArr": [
1,
2,
3
],
"SomeIntList": [
4,
5,
6
]
}
2. Jobject타입으로 만들어준다
유니티의 Json화는 `string`타입으로 반환해준다
반면 Newtonsoft패키지는 `Jobject`타입으로 반환해준다
이게 좋은점은
Json화 이후, 데이터의 추가 가공이 가능하다는 것이다
예를들어, 서버의 인풋구조에는 현재 시간의 `DateTime`이 있다고 치자
근데 게임내에서는 쓸일이없어서 변수로 추가하긴 싫다
그러면 Json직렬화 이후에 추가해주기 쉽다
[Button]
public void JobjectTest()
{
JObject jobj = JObject.FromObject(localSave);
jobj["date"] = DateTime.Now;
string jsonString = JsonConvert.SerializeObject(jobj);
}
위와 같이 `Jobject.FromObject()`로 직렬화 후 딕셔너리처럼 키,값 추가해주면 된다
그리고 최종적으로 `string`으로 직렬화한다
다만 이 케이스는 협업하는 입장에서는 이게 어디서 추가된건지 찾아 헤맬 수 있기때문에
상황을 가려서 쓰자
번외 - 좋은 점은 아니고 다른 점
유니티 `JsonUtility`의 경우 `[SerializeField] private`변수와 그 변수의 get 프로퍼티가 있으면 프로퍼티가 아닌
변수가 Json직렬화 된다
위에 언급했듯이 `JsonUtility`의 직렬화는 에디터 내부 인스펙터 직렬화랑 같고, 프로퍼티는 인스펙터에 안보이는게 기본이니까 그렇게 되는듯 하다
하지만 `NewtonSoft.Json`패키지의 경우 반대로 프로퍼티가 이 Json직렬화된다
아래는 예시다
- 위에 예시에도 썼던 데이터 클래스(이번엔 `[JsonIgnore]`는 없다)
[Serializable]
public class LocalSaveData
{
[SerializeField]
private int someInt;
[SerializeField]
private float someFloat;
[SerializeField]
private string someString;
[SerializeField]
private int[] someIntArr;
[SerializeField]
private List<int> someIntList;
public TestDataClass testDataClass;
#region 프로퍼티
public int SomeInt { get => someInt; set => someInt = value; }
public float SomeFloat { get => someFloat; set => someFloat = value; }
public string SomeString { get => someString; set => someString = value; }
public int[] SomeIntArr { get => someIntArr; set => someIntArr = value; }
public List<int> SomeIntList { get => someIntList; set => someIntList = value; }
#endregion
}
- 데이터
- Unity `JsonUtility.ToJson()`의 결과
→ 변수의 이름으로 소문자로 시작하는 이름이 직렬화된것을 확인할 수 있다
{
"someInt": 0,
"someFloat": 0.0,
"someString": "qwe",
"someIntArr": [1, 2, 3],
"someIntList": [4, 5, 6],
"testDataClass": {
"testString": "This is TestDataClass",
"testIntList": [7, 8, 9]
}
}
- NewtonSoft.Json `Jobject.FromObject()`의 결과
→ 프로퍼티의 이름으로 대문자로 시작하는 이름이 직렬화된것을 확인할 수 있다
{
"testDataClass": {
"testString": "This is TestDataClass",
"testIntList": [7, 8, 9]
},
"SomeInt": 0, // 프로퍼티의 이름을 따라간다(대문자로 시작)
"SomeFloat": 0.0,
"SomeString": "qwe",
"SomeIntArr": [1, 2, 3],
"SomeIntList": [4, 5, 6]
}
🍎결론
사실 Json직렬화 무시 어트리뷰트를 만들어볼려고 알아보던 중 뉴튼소프트 패키지에 이미있다는걸 알게됐다
잘 활용해서 json직렬화에 손이 덜가는 코드를 만들어보자
'Unity > C#' 카테고리의 다른 글
[Unity] Cinemachine으로 모바일 3인칭 카메라 만들기 (0) | 2024.07.04 |
---|---|
[C#] 빠르게 C# 단일 스크립트를 슥 작성하고 쇽 실행하는 법 (polyglot notebooks) (0) | 2024.06.27 |
[Unity] Unity 3D Game Kit Lite템플릿 Damageable스크립트 분석 (1) | 2024.05.22 |
[Unity] 짧은 팁 - 사용중인 시스템 메모리 용량 구하기 (0) | 2024.04.29 |
[C#] DateTime에서 남은시간 계산하기 (0) | 2023.02.25 |