1、介绍
上一篇中已经具备了将结构体实例利用反射动态的创建编辑栏的功能,本篇主要在前两篇的基础上增加了对泛型的处理以及无论是字段还是属性都可以进行处理。
如图所示:
本篇里处理的泛型为List类型,定义的测试结构体为:
[Serializable]
public struct Test
{
public double Lon;
public float Height;
public double Lat;
public void Init(double lon, float height, double lat)
{
Lon = lon;
Height = height;
Lat = lat;
}
}
[Serializable]
public struct Test_Data1
{
public int RouteID { get; set; }
public int Number;
public float Speed { get; set; }
public int OffsetTime;
public List<Test> ListData { get; set; }
}
其中Test_Data1结构体中,有字段也有属性,并且还有一个泛型ListData属性。这里要处理的是将前面四个字段和属性反射并生成编辑框的同时,还能动态的将ListData的数据信息也反射出来。
二、实现
1、在我们还不知道结构体里面会不会有泛型数据的时候,首先就应该对反射出来的属性和字段都进行判断,判断是否为泛型通过,“IsGenericType”来判断。无论是结构体是属性还是字段,我们都可以反射出来,只需要增加一个循环处理。代码如下
/// <summary>
/// 获取结构体非泛型的所有属性和字段,并返回由所有属性的名字和值组成的列表,Out 参数返回结构体或类中的泛型属性或字段
/// (这里只处理类或结构体只有一个List这样的泛型字段或属性)的整个列表
/// </summary>
/// <typeparam name="S">结构体类型</typeparam>
/// <typeparam name="L">结构体属性或字段列表中装载的数据类型</typeparam>
/// <param name="obj">结构体实例</param>
/// <param name="listGenericDatas">结构体属性或字段列表</param>
/// <returns></returns>
public static List<NP_SingleReflectInfo> GetVaule_ReflectMethod<S, L>(S obj, out List<L> listGenericDatas)
{
List<NP_SingleReflectInfo> tempList = new List<NP_SingleReflectInfo>();
listGenericDatas = new List<L>();
try
{
//遍历所有的属性
PropertyInfo[] tempPI = obj.GetType().GetProperties();
foreach (var info in tempPI)
{
//装载泛型属性
if (info.PropertyType.IsGenericType)
{
object tempListObj = info.GetValue(obj, null);
listGenericDatas = (List<L>)tempListObj;
}
else
{
string tempVarName = info.Name;
string tempVarVaule = info.GetValue(obj, null).ToString();
NP_SingleReflectInfo tempData = new NP_SingleReflectInfo();
tempData.Init(tempVarName, tempVarVaule);
//装载信息到列表中
tempList.Add(tempData);
}
}
//遍历所有的字段
FieldInfo[] tempFI = obj.GetType().GetFields();
foreach (var itemInfo in tempFI)
{
//装载泛型字段
if (itemInfo.FieldType.IsGenericType)
{
object tempListObj = itemInfo.GetValue(obj);
listGenericDatas = (List<L>)tempListObj;
}
else
{
string tempVarName = itemInfo.Name;
string tempVarVaule = itemInfo.GetValue(obj).ToString();
NP_SingleReflectInfo tempData = new NP_SingleReflectInfo();
tempData.Init(tempVarName, tempVarVaule);
//装载信息到列表中
tempList.Add(tempData);
}
}
}
catch (Exception e)
{
Debug.Log("获取类型数据错误" + e.Message);
return null;
}
return tempList;
}
属性和字段都分开处理,并将得到的字段和属性的两个重要信息“名字”和“值”装载成一个List返回,该List的结构体为:
/// <summary>
/// 反射获得结构体、类中的单个变量或属性的名字和值
/// </summary>
[Serializable]
public struct NP_SingleReflectInfo
{
/// <summary>
/// 变量的名字
/// </summary>
public string VariableName;
/// <summary>
/// 变量的值
/// </summary>
public string VariableValue;
public void Init(string name, string value)
{
VariableName = name;
VariableValue = value;
}
}
并且“Out”参数返回处理当前结构体的属性或字段里的泛型数据,如”Test_Data1“里面就会将”ListData“这个属性的数据反射出来,并赋值给”Out“的参数
2、使用的代码如:
public void BtnCreate_OnClick()
{
testData1.ListData = new List<Test>();
Test t1 = new Test();
Test t2 = new Test();
t1.Init(10, 20, 30);
t2.Init(0.2, 0.45f, 0.67);
testData1.ListData.Add(t1);
testData1.ListData.Add(t2);
listSingleReflectInfo = GetVaule_ReflectMethod(testData1, out listRelctInfoListData);
//然后根据这些字段创建一个ui编辑条
for (int i = 0; i < listSingleReflectInfo.Count; i++)
{
UI2D_SubObjEditorAttr tempEPPA = Instantiate(prefabSubObjEditor);
tempEPPA.transform.SetParent(transform);
tempEPPA.transform.localPosition = new Vector3(0, -intervalHeight * i, 0);
tempEPPA.transform.localScale = Vector3.one;
tempEPPA.Init(null, listSingleReflectInfo[i].VariableName, listSingleReflectInfo[i].VariableValue);
}
//创建结构体列表
for (int i = 0; i < listRelctInfoListData.Count ; i++)
{
UI2D_SubObjEditorAttr tempEPPA = Instantiate(prefabSubObjEditor);
tempEPPA.transform.SetParent(scrollViewContents.transform);
tempEPPA.transform.localPosition = new Vector3(0, -intervalHeight * i, 0);
tempEPPA.transform.localScale = Vector3.one;
tempEPPA.Init(null,"ID "+ i.ToString(),"Type " +listRelctInfoListData[i].ToString());
}
}
处理非泛型的属性和字段就还是按照以前的处理方式,直接将变量的名字和值现实出来。对于泛型的处理,我们已经得到了该泛型的数据。如此处的”ListData“数据。本篇只将该List数据列表中元素的序号和类型显示出来。
三、总结
1、对于结构体里的泛型数据进行了处理,得到了该泛型数据
2、无论是字段还是属性都可以处理