#c# #unity3d #reflection
#c# #unity3d #отражение
Вопрос:
Я пытаюсь получить содержимое JSON диалога и скопировать его свойства (сохраненные в диалогах классов) в другой класс, производный от MonoBehaviour (DialogueManager). В любом случае, метод GetValue возвращает null, даже если getProperty возвращает правильные имена свойств. Я не могу просто прочитать Json в DialogueManager, потому что JsonUtility, по-видимому, необходимо экспортировать в класс, отличающийся от MonoBehaviour.
using System.IO;
using UnityEngine;
public class DialogueManager : MonoBehaviour
{
//999 IS RETURN TO MENU
//1000 IS CLOSE GAME
public static DialogueManager instance = null;
Dialogues dial;
public string text1 { get; set; }
public string choices1 { get; set; }
public string consequences1 { get; set; }
public string text2 { get; set; }
public string choices2 { get; set; }
public string consequences2 { get; set; }
public string text3 { get; set; }
public string choices3 { get; set; }
public string consequences3 { get; set; }
public string text4 { get; set; }
public string choices4 { get; set; }
public string consequences4 { get; set; }
public string text5 { get; set; }
public string choices5 { get; set; }
public string consequences5 { get; set; }
public string text6 { get; set; }
public string choices6 { get; set; }
public string consequences6 { get; set; }
public string text7 { get; set; }
public string choices7 { get; set; }
public string consequences7 { get; set; }
public string text8 { get; set; }
public string choices8 { get; set; }
public string consequences8 { get; set; }
public string text9 { get; set; }
public string choices9 { get; set; }
public string consequences9 { get; set; }
public string text10 { get; set; }
public string choices10 { get; set; }
public string consequences10 { get; set; }
public string text11 { get; set; }
public string choices11 { get; set; }
public string consequences11 { get; set; }
public string text12 { get; set; }
public string choices12 { get; set; }
public string consequences12 { get; set; }
public string text13 { get; set; }
public string choices13 { get; set; }
public string consequences13 { get; set; }
public string text14 { get; set; }
public string choices14 { get; set; }
public string consequences14 { get; set; }
public string text15 { get; set; }
public string choices15 { get; set; }
public string consequences15 { get; set; }
public string text16 { get; set; }
public string choices16 { get; set; }
public string consequences16 { get; set; }
public string text17 { get; set; }
public string choices17 { get; set; }
public string consequences17 { get; set; }
public string text18 { get; set; }
public string choices18 { get; set; }
public string consequences18 { get; set; }
public string text19 { get; set; }
public string choices19 { get; set; }
public string consequences19 { get; set; }
public string text20 { get; set; }
public string choices20 { get; set; }
public string consequences20 { get; set; }
public string text21 { get; set; }
public string choices21 { get; set; }
public string consequences21 { get; set; }
public string text22 { get; set; }
public string choices22 { get; set; }
public string consequences22 { get; set; }
public string text23 { get; set; }
public string choices23 { get; set; }
public string consequences23 { get; set; }
string fixedName;
string[] splits;
string text;
int[] consequences;
private void Awake()
{
if(instance == null)
{
instance = this;
}
else
{
enabled = false;
}
dial = new Dialogues();
StreamReader sR = new StreamReader(Application.dataPath "/GameData/dialogues.json");
string json = sR.ReadToEnd();
dial = JsonUtility.FromJson<Dialogues>(json);
Assign();
}
//This doesn't work for some reason
public void Assign()
{
foreach(var property in typeof(Dialogues).GetProperties())
{
typeof(DialogueManager).GetProperty(property.Name).SetValue(this, property.GetValue(dial));
}
}
public string GetText(int currentText)
{
fixedName = "text" currentText;
string output = typeof(DialogueManager).GetProperty(fixedName).GetValue(this, null).ToString();
return output;
}
public string GetTextChoices(int textNum)
{
fixedName = "choices" textNum;
string output = typeof(DialogueManager).GetProperty(fixedName).GetValue(this, null).ToString();
return output;
}
public int[] GetChoicesConsequences(int textNum)
{
fixedName = "consequences" textNum;
string output = typeof(DialogueManager).GetProperty(fixedName).GetValue(this, null).ToString();
splits = output.Split('§');
consequences = new int[splits.Length];
for (int i = 0; i < splits.Length; i )
{
consequences[i] = int.Parse(splits[i]);
}
return consequences;
}
private void DumbAssign()
{
text1 = dial.text1;
choices1 = dial.choices1;
consequences1 = dial.consequences1;
text2 = dial.text2;
choices2 = dial.choices2;
consequences2 = dial.consequences2;
text3 = dial.text3;
choices3 = dial.choices3;
consequences3 = dial.consequences3;
text4 = dial.text4;
choices4 = dial.choices4;
consequences4 = dial.consequences4;
text5 = dial.text5;
choices5 = dial.choices5;
consequences5 = dial.consequences5;
text6 = dial.text6;
choices6 = dial.choices6;
consequences6 = dial.consequences6;
text7 = dial.text7;
choices7 = dial.choices7;
consequences7 = dial.consequences7;
text8 = dial.text8;
choices8 = dial.choices8;
consequences8 = dial.consequences8;
text9 = dial.text9;
choices9 = dial.choices9;
consequences9 = dial.consequences9;
text10 = dial.text10;
choices10 = dial.choices10;
consequences10 = dial.consequences10;
text11 = dial.text11;
choices11 = dial.choices11;
consequences11 = dial.consequences11;
text12 = dial.text12;
choices12 = dial.choices12;
consequences12 = dial.consequences12;
text13 = dial.text13;
choices13 = dial.choices13;
consequences13 = dial.consequences13;
text14 = dial.text14;
choices14 = dial.choices14;
consequences14 = dial.consequences14;
text15 = dial.text15;
choices15 = dial.choices15;
consequences15 = dial.consequences15;
text16 = dial.text16;
choices16 = dial.choices16;
consequences16 = dial.consequences16;
text17 = dial.text17;
choices17 = dial.choices17;
consequences17 = dial.consequences17;
text18 = dial.text18;
choices18 = dial.choices18;
consequences18 = dial.consequences18;
text19 = dial.text19;
choices19 = dial.choices19;
consequences19 = dial.consequences19;
text20 = dial.text20;
choices20 = dial.choices20;
consequences20 = dial.consequences20;
text21 = dial.text21;
choices21 = dial.choices21;
consequences21 = dial.consequences21;
text22 = dial.text22;
choices22 = dial.choices22;
consequences22 = dial.consequences22;
}
}
[System.Serializable]
public class Dialogues
{
public string text1 { get; set; }
public string choices1 { get; set; }
public string consequences1 { get; set; }
public string text2 { get; set; }
public string choices2 { get; set; }
public string consequences2 { get; set; }
public string text3 { get; set; }
public string choices3 { get; set; }
public string consequences3 { get; set; }
public string text4 { get; set; }
public string choices4 { get; set; }
public string consequences4 { get; set; }
public string text5 { get; set; }
public string choices5 { get; set; }
public string consequences5 { get; set; }
public string text6 { get; set; }
public string choices6 { get; set; }
public string consequences6 { get; set; }
public string text7 { get; set; }
public string choices7 { get; set; }
public string consequences7 { get; set; }
public string text8 { get; set; }
public string choices8 { get; set; }
public string consequences8 { get; set; }
public string text9 { get; set; }
public string choices9 { get; set; }
public string consequences9 { get; set; }
public string text10 { get; set; }
public string choices10 { get; set; }
public string consequences10 { get; set; }
public string text11 { get; set; }
public string choices11 { get; set; }
public string consequences11 { get; set; }
public string text12 { get; set; }
public string choices12 { get; set; }
public string consequences12 { get; set; }
public string text13 { get; set; }
public string choices13 { get; set; }
public string consequences13 { get; set; }
public string text14 { get; set; }
public string choices14 { get; set; }
public string consequences14 { get; set; }
public string text15 { get; set; }
public string choices15 { get; set; }
public string consequences15 { get; set; }
public string text16 { get; set; }
public string choices16 { get; set; }
public string consequences16 { get; set; }
public string text17 { get; set; }
public string choices17 { get; set; }
public string consequences17 { get; set; }
public string text18 { get; set; }
public string choices18 { get; set; }
public string consequences18 { get; set; }
public string text19 { get; set; }
public string choices19 { get; set; }
public string consequences19 { get; set; }
public string text20 { get; set; }
public string choices20 { get; set; }
public string consequences20 { get; set; }
public string text21 { get; set; }
public string choices21 { get; set; }
public string consequences21 { get; set; }
public string text22 { get; set; }
public string choices22 { get; set; }
public string consequences22 { get; set; }
public string text23 { get; set; }
public string choices23 { get; set; }
public string consequences23 { get; set; }
}
РЕДАКТИРОВАТЬ 1: теперь я отредактировал скрипт, чтобы использовать только класс Dialogues для свойств, но я все еще не знаю, как получить свойства (мне нужно сделать это таким образом, потому что там будет более 250 текстов)
using System.IO;
using UnityEngine;
public class DialogueManager : MonoBehaviour
{
//999 IS RETURN TO MENU
//1000 IS CLOSE GAME
public static DialogueManager instance = null;
string fixedName;
private Dialogues dial;
public Dialogues Dial { get { return dial; } }
string[] splits;
string text;
int[] consequences;
private void Awake()
{
if(instance == null)
{
instance = this;
}
else
{
enabled = false;
}
dial = new Dialogues();
StreamReader sR = new StreamReader(Application.dataPath "/GameData/dialogues.json");
string json = sR.ReadToEnd();
dial = JsonUtility.FromJson<Dialogues>(json);
}
public string GetText(int currentText)
{
fixedName = "text" currentText;
string output = instance.Dial.GetType().GetProperty(fixedName).GetValue(dial).ToString();
return output;
}
public string GetTextChoices(int textNum)
{
fixedName = "choices" textNum;
string output = typeof(DialogueManager).GetProperty(fixedName).GetValue(this, null).ToString();
return output;
}
public int[] GetChoicesConsequences(int textNum)
{
fixedName = "consequences" textNum;
string output = typeof(DialogueManager).GetProperty(fixedName).GetValue(this, null).ToString();
splits = output.Split('§');
consequences = new int[splits.Length];
for (int i = 0; i < splits.Length; i )
{
consequences[i] = int.Parse(splits[i]);
}
return consequences;
}
}
[System.Serializable]
public class Dialogues
{
public string text1;
public string choices1;
public string consequences1;
public string text2;
public string choices2;
public string consequences2;
public string text3;
public string choices3;
public string consequences3;
public string text4;
public string choices4;
public string consequences4;
public string text5;
public string choices5;
public string consequences5;
public string text6;
public string choices6;
public string consequences6;
public string text7;
public string choices7;
public string consequences7;
public string text8;
public string choices8;
public string consequences8;
public string text9;
public string choices9;
public string consequences9;
public string text10;
public string choices10;
public string consequences10;
public string text11;
public string choices11;
public string consequences11;
public string text12;
public string choices12;
public string consequences12;
public string text13;
public string choices13;
public string consequences13;
public string text14;
public string choices14;
public string consequences14;
public string text15;
public string choices15;
public string consequences15;
public string text16;
public string choices16;
public string consequences16;
public string text17;
public string choices17;
public string consequences17;
public string text18;
public string choices18;
public string consequences18;
public string text19;
public string choices19;
public string consequences19;
public string text20;
public string choices20;
public string consequences20;
public string text21;
public string choices21;
public string consequences21;
public string text22;
public string choices22;
public string consequences22;
public string text23;
public string choices23;
public string consequences23;
}
Ответ №1:
Прежде всего, не используйте Свойства для Dialogues
класса! Свойства (без каких-либо резервных полей) никогда не (де) сериализуются.
Это причина, по которой вы получаете null
from GetValue
, потому что свойства никогда не задаются.
Удалите все {get; set;}
и сделайте эти переменные довольно простыми полями
public string text1;
public string choices1;
....
Вы должны использовать свойства только там, где они вам действительно нужны — обычно для того, чтобы иметь доступные только для чтения свойства доступа или для того, чтобы проверить некоторые значения, прежде чем вы получите их из external .
То же самое относится и ко всем этим свойствам в DialogueManager
.
Если вы действительно хотите остаться со свойствами (в DialogueManager
), вам следует скорее напрямую читать и записывать в dial
ссылку, которая у вас есть, например,
public string text1
{
get { return dial.text1; }
set { dial.text1 = value; }
}
Однако, если вы просто сделаете либо
public Dialogues Dial;
или, по крайней мере, дайте ему свойство только для чтения
private Dialogues dial;
public Dialogues Dial
{
get { return dial; }
}
любой другой компонент может просто получить доступ к этим значениям через это поле:
dialogueManagerReference.Dial.text1
и вам не нужно копировать какие-либо значения.
Кроме того, если вы используете
public Dialogues Dial;
или
[SerializeField] private Dialogues Dial;
вы также можете редактировать / отлаживать эти значения непосредственно в инспекторе Unity.
И, наконец, эта структура данных выглядит немного странно, повторяя все эти имена и типы с числами… У меня нет вашего файла JSON, так что, возможно, это способ, которым вы их получаете, но вы уверены, что в нем нет списка / массива? Я бы предпочел ожидать здесь структуру данных, например,
[Serializable]
public class Dialogues
{
public Dialogue[] DialogueList;
}
[Serializable]
public class Dialogue
{
public string Text;
public string[] Choices;
public string[] Consequences;
}
и соответствующий JSON будет выглядеть, например, так:
{
"DialogueList" : [
{
"Text" : "some text",
"Choices" : [
"Option A" , "Option B", "Option C"
],
"Consequences" : [
"Good Boy!", "Oh No!", "Well maybe acceptable ..."
]
},
{
"Text" : "some other text",
"Choices" : [
"Option Left" , "Option Right"
],
"Consequences" : [
"Yeay :)", "Neyy :("
]
},
... and 21 more entries
]
}
Комментарии:
1. Раньше я пытался получить массивы из GetValue(), но безуспешно. С тех пор я разделил каждый текст на 3 разных свойства, которые мне нужны:(.
2. Если это возможно для вас, вы должны изменить JSON для использования массивов. А затем доступ к соответствующим значениям с использованием индексов, таких как, например
Dial[0].Choices[2]
, и не использовать для этого отражение.. это очень плохо с точки зрения производительности
Ответ №2:
В конце концов, я понял это. Я изменил код, чтобы использовать массив объектов, с помощью JsonHelper.
Dialogues.json:
{
"Items": [
{
"id": "1",
"text": "7:15 A.M. School starts at 8:05",
"choices": "",
"consequences": "2"
},
{
"id": "2",
"text": "What do you want to do?",
"choices": "1: Sleep for a while; 2: Get up",
"consequences": "3?5"
}
]
}
DialogueManager.cs:
using System.IO;
using UnityEngine;
using System;
using System.Security.Cryptography;
using System.Text;
public static class JsonHelper
{
public static T[] FromJson<T>(string json)
{
Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
return wrapper.Items;
}
public static string ToJson<T>(T[] array)
{
Wrapper<T> wrapper = new Wrapper<T>();
wrapper.Items = array;
return JsonUtility.ToJson(wrapper);
}
public static string ToJson<T>(T[] array, bool prettyPrint)
{
Wrapper<T> wrapper = new Wrapper<T>();
wrapper.Items = array;
return JsonUtility.ToJson(wrapper, prettyPrint);
}
[Serializable]
private class Wrapper<T>
{
public T[] Items;
}
}
public class DialogueManager : MonoBehaviour
{
[Serializable]
public class Dialogue
{
public int id;
public string text;
public string choices;
public string consequences;
public Dialogue(int id, string text, string choices, string consequences)
{
this.id = id;
this.text = text;
this.choices = choices;
this.consequences = consequences;
}
}
Dialogue[] dial;
public static DialogueManager instance = null;
string[] splits;
int[] consequences;
private void Awake()
{
if(instance == null)
{
instance = this;
}
else
{
enabled = false;
}
StreamReader sR = new StreamReader(Application.dataPath "/GameData/dialogues.json");
//NON CRITTOGRAFIA
string json = sR.ReadToEnd();
//CRITTOGRAFIA
//string crypted = sR.ReadToEnd();
//string json = Encrypt.DecryptString(crypted, "think");
dial = JsonHelper.FromJson<Dialogue>(json);
}
public string GetText(int currentText)
{
return dial[currentText - 1].text;
}
public string GetTextChoices(int textNum)
{
return dial[textNum - 1].choices;
}
public int[] GetChoicesConsequences(int textNum)
{
string output = dial[textNum - 1].consequences;
splits = output.Split('?');
consequences = new int[splits.Length];
for (int i = 0; i < splits.Length; i )
{
consequences[i] = int.Parse(splits[i]);
}
return consequences;
}
}