Unity中如何优雅的将Excel单元格数据转换成基础类型或者数组

在游戏开发中经常需要把策划提供的Excel表格转换成Unity可以序列化读取的ScriptableObject对象。不同的单元格数据可能会被转换成不同的类型,如string,int,float,bool,Enum等。为了简洁转换代码,可以定义一个泛型方法ToValue统一处理。

using System;

public class ExcelReader
{
    protected T ToValue<T>(string s)
    {
        Type type = typeof(T);

        object o = null;
        if (type.IsEnum)
        {
            o = Enum.Parse(type, s);
        }
        else if (typeof(string).Equals(type))
        {
            o = s;
        }
        else if (typeof(bool).Equals(type))
        {
            o = s.Equals("1");
        }
        else if (typeof(int).Equals(type))
        {
            int value = 0;
            int.TryParse(s, out value);
            o = value;
        }
        else if (typeof(float).Equals(type))
        {
            float value = 0f;
            float.TryParse(s, out value);
            o = value;
        }

        return (T)o;
    }
}

大部分情况下,这个方法已经够用了。但是它不能处理这种数据。单元格数据
对于这个需求,首先想到的是定义一个专门处理数组的转换方法ToValueArray

    public static readonly char[] separators = { '|', ',' };

    public T[] ToValueArray<T>(string s)
    {
        var strs = s.Split(separators, StringSplitOptions.RemoveEmptyEntries);
        T[] array = new T[strs.Length];
        for (int i = 0; i < strs.Length; ++i)
        {
            array[i] = ToValue<T>(strs[i]);
        }

        return array;
    }

但是这样写转换代码的时候可能就要一会儿ToValue(XX),又一会儿ToValueArray(XX)。有没有办法直接实现类似ToValue(XX)呢?这样就一水的ToValue下来,别提有多整洁优雅了。

通过查阅资料,我知道

  1. Type的属性IsArray可以判定类型是否是数组。
  2. Type的方法GetElementType可以获取数组的元素类型。
  3. 通过反射可以创建数组。Activator.CreateInstance(数组元素类型, new object[] { 数组长度 });
  4. 数组类型都具有SetValue方法可以设置数组元素,有好几个重载。感兴趣的读者可以调用一下代码打印看看。
Type t = Type.GetType("System.Int32[]");
foreach(MethodInfo mi in t.GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
    Console.WriteLine(mi.Name);
}
  1. MethodInfoMakeGenericMethod方法可以生成泛型方法对应的实例方法,毕竟泛型方法没有办法直接Invoke。

结合以上5点,我可以在ToValue里判断当前类型是否是数组,是的话获取对应的数组元素类型,并创建单元格数组对应长度的数组,通过反射调用ToValue本身获取每个string元素对应的值,再通过SetValue一一设置。

        if (type.IsArray)
        {
            string[] strs = s.Split(separators, StringSplitOptions.RemoveEmptyEntries);

            Type elementType = type.GetElementType();

            MethodInfo mi = GetType().GetMethod("ToValue", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.ExactBinding);
            mi = mi.MakeGenericMethod(elementType);

            object array = Activator.CreateInstance(type, new object[] { strs.Length });
            MethodInfo setValue = type.GetMethod("SetValue", new Type[2] { typeof(object), typeof(int) });
            for (int i = 0; i < strs.Length; i++)
            {
                object v = mi.Invoke(this, new object[] { strs[i], false });
                setValue.Invoke(array, new object[] { v, i });
            }

            return (T)array;
        }

这样转换代码就整齐多了。在这里插入图片描述
另外还可以制作一个转换代码的生成工具。只要我们定好表格的数据结构,就可以由工具批量的生成转换代码,从而从天量的表格转换中解脱出来。这里就不一一赘述了。

你可能感兴趣的:(C#,Unity)