weixin_33538392
weixin_33538392
采纳率33.3%
2018-07-28 17:17

C#动态生成类的问题,取得程序集出了问题

40

需求就是在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
不知道在哪里上传附件,就放盘里了。希望大佬们帮忙解答一下,非常感谢。

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

2条回答

  • caozhy 从今以后生命中的每一秒都属于我爱的人 3年前

    另外,你是在mono上跑的,你还得确认下mono支持codedom,以及在unity下,你有权限调用编译器生成程序集并加载。
    我从来没看到有人在mono上这么写过。

    点赞 评论 复制链接分享
  • caozhy 从今以后生命中的每一秒都属于我爱的人 3年前

    调试下getData();是否获取到了数据
    FileStream fs = new FileStream("/Users/lijiesheng/Desktop/test.txt", FileMode.Create);
    这个是否有输出正确的源代码
    这个源代码的内容贴出来看看,它是否包含正确的引用
    它是否包含中文、特殊符号等,并且你的编码是否正确
    NewAssembly(_classSource.ToString());
    如果你的源代码不正确,这里会返回null

    点赞 评论 复制链接分享

相关推荐