需求就是在unity中,解析一个Excel文件,根据解析到的信息动态生成类,并将数据存入(一个继承ScriptableOjbect类的对象里,这里具体记不清了)
前面解析Excel好像都没什么问题,类的源码信息存到了classSource里,尝试过输出到txt里面看过,所输出的类结构没有问题。
问题出在后面的编译代码和获取编译后的程序集,unity报错“NullReferenceException: Object reference not set to an instance of an object
DynamicClass.setCode () (at Assets/Scripts/DynamicClass.cs:80)
DynamicClass.Start () (at Assets/Scripts/DynamicClass.cs:92)
动态创建类是参考http://www.cnblogs.com/firstyi/archive/2008/03/07/1094652.html这里的
新手希望能解答一下,谢谢。
//ExcelData.cs 存储从Excel解析来的类信息和数据
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExcelData : ScriptableObject
{
[SerializeField]
public struct classVar
{
public string varName;
public string varType;
};
public string _className;
public List<classVar> _variable;
public List<List<int>> _data;
}
//ExcelManager.cs 解析Excel文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using NPOI.SS.UserModel;
using NPOI.HSSF.UserModel;
using NPOI.XSSF.UserModel;
using System.IO;
using UnityEngine.UI;
public class ExcelManager
{
public static ExcelManager _instance = null;
public static ExcelManager Instance
{
get
{
if (null == _instance)
return new ExcelManager();
else
return _instance;
}
}
public int _invalidRow = 0;
public int _dataIndex = -1;
public ExcelData ReadExcel()
{
ExcelData excelData = ScriptableObject.CreateInstance<ExcelData>();
excelData._variable = new List<ExcelData.classVar>();
excelData._data = new List<List<int>>();
//测试
string fileName = "/Users/lijiesheng/Desktop/test.xlsx";
IWorkbook workbook = null;
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
if (fileName.IndexOf(".xlsx") > 0)
{
//2007版
workbook = new XSSFWorkbook(fileStream);
}
else if (fileName.IndexOf(".xls") > 0)
{
//2003版
workbook = new HSSFWorkbook(fileStream);
}
else
{
Debug.LogError("File is not existed.");
}
ISheet sheet = workbook.GetSheetAt(0);
excelData._className = sheet.SheetName;
excelData._className = excelData._className.Substring(1, excelData._className.Length - 1);
IRow row;
for (int i = 0; i < sheet.LastRowNum; ++i)
{
row = sheet.GetRow(i);
if (row != null)
{
//若该行首列内容以'#'开头,则跳过该行
string tmp = row.GetCell(0).ToString();
if (tmp[0] == '#')
{
++_invalidRow;
continue;
}
for (int j = 0; j < row.LastCellNum; ++j)
{
string cellValue = row.GetCell(j).ToString();
if (cellValue[0] == '&')
{
//内容以'&'开头则记录变量名和类型
int index = cellValue.IndexOf('|');
string tmpVarName = cellValue.Substring(1, index - 1);
tmpVarName.ToLower();
string tmpVarType = cellValue.Substring(index + 1, cellValue.Length - (index + 1));
tmpVarName.ToLower();
ExcelData.classVar cv;
cv.varName = tmpVarName;
cv.varType = tmpVarType;
excelData._variable.Add(cv);
}
else
{
//否则记录数据
if (excelData._data.Count <= i - _invalidRow)
{
++_dataIndex;
excelData._data.Add(new List<int>());
//_data[_dataIndex] = new List<int>();
excelData._data[_dataIndex].Add(int.Parse(cellValue));
}
else
{
excelData._data[_dataIndex].Add(int.Parse(cellValue));
}
}
}
}
}
fileStream.Close();
workbook.Close();
return excelData;
////测试
//Debug.Log(excelData._className);
//foreach(var pair in excelData._variable)
//{
// Debug.Log(pair.varName + " " + pair.varType);
//}
//for (int i = 0; i < excelData._data.Count; ++i)
//{
// Debug.Log("_data.Count" + i + " " + excelData._data[i].Count);
// for (int j = 0; j < excelData._data[i].Count; ++j)
// {
// Debug.Log(excelData._data[i][j]);
// }
//}
}
}
//DynamicClass.cs 动态创建类
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
using System.CodeDom;
using System;
using System.IO;
using UnityEditor;
public class DynamicClass : MonoBehaviour {
ExcelData _excelData;
public Assembly _assembly;
//创建编译器实例
public CSharpCodeProvider provider;
//设置编译参数
public CompilerParameters paras;
public static StringBuilder _classSource;
public void getData()
{
_excelData = ExcelManager.Instance.ReadExcel();
}
//动态创建类
public Assembly NewAssembly(string classSource)
{
provider = new CSharpCodeProvider();
paras = new CompilerParameters();
paras.GenerateExecutable = false;
paras.GenerateInMemory = true;
paras.OutputAssembly = "/Users/lijiesheng/Desktop/" + _excelData._className + ".dll";
//编译代码
CompilerResults result = provider.CompileAssemblyFromSource(paras, classSource);
//获取编译后的程序集
Assembly assembly = result.CompiledAssembly;
return assembly;
}
//[MenuItem("Tools/Generate Class")]
public void SetCode()
{
getData();
_classSource = new StringBuilder();
_classSource.Append("using System;\n");
_classSource.Append("using UnityEngine;\n");
_classSource.Append("using System.Collections;\n");
_classSource.Append("using System.Collections.Generic;\n\n");
_classSource.Append("[Serializable]\n");
_classSource.Append("public class " + _excelData._className +"\n");
_classSource.Append("{\n");
foreach (var pair in _excelData._variable)
{
_classSource.Append(" public " + pair.varType + " " + pair.varName + ";\n");
//Debug.Log(pair.varType + " " + pair.varName);
}
_classSource.Append("}\n");
//验证文本
FileStream fs = new FileStream("/Users/lijiesheng/Desktop/test.txt", FileMode.Create);
byte[] data = System.Text.Encoding.Default.GetBytes(_classSource.ToString());
fs.Write(data, 0, data.Length);
fs.Flush();
fs.Close();
_assembly = NewAssembly(_classSource.ToString());
////---TODO---
//object generatedClass = _assembly.CreateInstance(_excelData._className);
//PropertyInfo[] infos = generatedClass.GetType().GetProperties();
//foreach (var info in infos)
//{
// Debug.Log(info.Name);
//}
}
void Start()
{
SetCode();
}
}
工程文件:链接: https://pan.baidu.com/s/1ylpOGiaPTT0gIKsMD39b7A 密码: hxw5
不知道在哪里上传附件,就放盘里了。希望大佬们帮忙解答一下,非常感谢。