xLua_002 C#访问Lua

1、接收全局变量

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class CSharpCallLua : MonoBehaviour
{
    void Start()
    {
        LuaEnv env = new LuaEnv();

        env.DoString("require'CSharpCallLua'");
        //数据接收 Get<类型>(lua变量名)
        //number --- int float double
        int a = env.Global.Get<int>("a"); // 获取到Lua 里面的 全局变量 a
        string b = env.Global.Get<string>("b");
        bool isDie = env.Global.Get<bool>("isDie");
        print(a);print(b);print(isDie);


        env.Dispose();
    }
}

CSharpCallLua.lua.txt

Lua 复制代码
a= 100
b="jin"
isDie = false

2、访问table类型

方法1:将Table映射到普通的Class类或 Strut结构体

弊端:

  • 耗费性能
  • 在C#文件中对table的内容进行修改,不会改变lua文件中的值 反之,亦然

可以通过把类型加到GCOptimize生成降低开销

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class CSharpCallLua : MonoBehaviour
{
    void Start()
    {
        LuaEnv env = new LuaEnv();

        env.DoString("require'CSharpCallLua'");
        //访问table类型
        //方法1:将Table映射到普通的Class类或 Strut结构体
        Person p= env.Global.Get<Person>("person");
        print(p.name + "-" + p.age);

        env.Dispose();
    }
    class Person
    {
        public string name;
        public int age;
    }
}

CSharpCallLua.lua.txt

Lua 复制代码
person= {
	name ="jin" ,
	age=100
}

方法2:将Table映射到一个interface 接口

易出问题:

interface 要加上特性[CSharpCallLua]

interface 要加上public

如果出现报错:InvalidCastException: This type must add to CSharpCallLua: IPerson

cs 复制代码
using UnityEngine;
using XLua;

[CSharpCallLua]
public interface IPerson
{
    string name { get; set; }
    int age { get; set; }
}

public class CSharpCallLua : MonoBehaviour
{
    void Start()
    {
        LuaEnv env = new LuaEnv();
        env.DoString("require 'CSharpCallLua'");

        // 确保使用 IPerson 接口
        IPerson p = env.Global.Get<IPerson>("person");
        Debug.Log(p.name + " - " + p.age); // 应输出 "jin - 100"

        env.Dispose();
    }
}

√ 解决方法:按顺序点击

方法3:更轻量级的by value方式:映射到Dictionary<>,List<>

1)利用Dictionary<> 字典

CSharpCallLua.lua.txt

cs 复制代码
person= {
	name ="jin" ,
	age=100,
	12,2,2,2,2,"jin",true,3.3,
	eat=function(self ,a ,b)
	    print (a+b)
	end 
}

CSharpCallLua.cs

cs 复制代码
using UnityEngine;
using XLua;
public class CSharpCallLua : MonoBehaviour
{
    void Start()
    {
        LuaEnv env = new LuaEnv();
        env.DoString("require'CSharpCallLua'");
        
        //Dictionary<> 字典
        Dictionary<string,object> dict = env.Global.Get<Dictionary<string, object>>("person");
        foreach (var key in dict.Keys)
        {
            print(key + "-" + dict[key]);
        }
        env.Dispose();
    }
}
  • Dictionary<string,object> : 使用object是因为值,什么类型都有

输出结果:

2)利用List<> 字典

CSharpCallLua.cs

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class CSharpCallLua : MonoBehaviour
{
    void Start()
    {
        LuaEnv env = new LuaEnv();

        env.DoString("require'CSharpCallLua'");

        //List<>列表
        List<object> list = env.Global.Get<List<object>>("person");
        foreach (var o in list)
        {
            print(o);
        }

        env.Dispose();
    }
}

输出结果:

List<object> list = env.Global.Get<List<object>>("person"); 改为

List<int> list = env.Global.Get<List<int>>("person");

输出结果:

可以二者结合使用 输出完整的 Table表

方法4:另外一种by ref方式:映射到LuaTable类

LuaTable 是Xlua提供给C# 的一个类,可以得到所有的数据 ,比方法2要慢,没有类型检查

(不常用)

CSharpCallLua.cs

cs 复制代码
using UnityEngine;
using XLua;
public class CSharpCallLua : MonoBehaviour
{
    void Start()
    {
        LuaEnv env = new LuaEnv();
        env.DoString("require'CSharpCallLua'");

        //方法4:利用LuaTablefangs
        LuaTable tab = env.Global.Get<LuaTable>("person");

        print(tab.Get<string>("name"));
        print(tab.Get<int>("age"));
        
        env.Dispose();
    }
}

输出结果:

3、访问一个全局的function 函数)

方法1:映射到delegate 委托

1)无参版

CSharpCallLua.lua.txt

cs 复制代码
function add(a,b)
	print(a+b)
	end

CSharpCallLua.cs

cs 复制代码
using UnityEngine;
using XLua;
using System;

public class CSharpCallLua : MonoBehaviour
{
    void Start()
    {
        LuaEnv env = new LuaEnv();

        env.DoString("require'CSharpCallLua'");
        
        //function
        Action<int ,int> act1 = env.Global.Get<Action<int,int>>("add");
        act1(36,78);
        act1 = null;

        //利用委托delegate
        Add add = env.Global.Get<Add>("add");
        add(12, 78);
        add = null;
        
        env.Dispose();

    }

    // 添加特性 不加报错
    [CSharpCallLua]
    delegate void Add(int a, int b);
}

输出结果:

报错:InvalidOperationException: try to dispose a LuaEnv with C# callback!

通常是因为在销毁Lua环境(LuaEnv)时,仍有未释放的C#回调(如委托、事件绑定)残留。

原因:因为C#的GC回收机制导致的,在同一帧

解决方法:利用生命周期

1.OnDisable() 用于可逆操作

  • 适合临时释放资源,便于对象重新激活时恢复
  • 解绑事件、停止逻辑

2.OnDestroy() 用于不可逆操作

  • 确保对象销毁后无残留引用
  • 彻底释放资源

代码修改:

cs 复制代码
using System;
using UnityEngine;
using XLua;

public class CSharpCallLua : MonoBehaviour
{
    public LuaEnv env = null;  //先声明LuaEnv为公共变量

    void Start()
    {
        LuaEnv env = new LuaEnv();
        env.DoString("require'CSharpCallLua'");

        //function
        Action<int, int> act1 = env.Global.Get<Action<int, int>>("add");
        act1(36, 78);

        Add add = env.Global.Get<Add>("add");
        add(12, 78);
    }

    //释放资源
    private void OnDisable()
    {
        if (env != null)
        {
            env.Dispose();
            env = null;
        }
    }

    [CSharpCallLua]
    delegate void Add(int a, int b);
}

2)有参数

CSharpCallLua.lua.txt

添加return 返回值

Lua 复制代码
function add(a,b)
	print(a+b)
	return a+b  
	end

代码修改:

cs 复制代码
using System;
using UnityEngine;
using XLua;

//void -> int 
//将delegate委托独立出来
[CSharpCallLua]
public delegate int Add(int a, int b);

public class CSharpCallLua : MonoBehaviour
{
    public LuaEnv env = null;
    void Start()
    {
        LuaEnv env = new LuaEnv();
        env.DoString("require'CSharpCallLua'");

        Add add = env.Global.Get<Add>("add");
        int res=add(12, 78);  //返回值赋值
        print(res);
    }

    private void OnDisable()
    {
        if (env != null)
        {
            env.Dispose();
            env = null;
        }
    }
}

如果报错,重复 interface报错问题的解决方法

3)多参数

利用out参数接收多余的数据(ref也可以,但是定义要先赋值 例:int resa=0;)

CSharpCallLua.lua.txt

Lua 复制代码
function add(a,b)
	return a+b,a,b
	end

代码修改:

cs 复制代码
using System;
using UnityEngine;
using XLua;

//在delegate委托中添加out 因为是整数,所以用int类型
[CSharpCallLua]
public delegate int Add(int a, int b,out int resa,out int resb);

public class CSharpCallLua : MonoBehaviour
{
    public LuaEnv env = null;

    void Start()
    {
        LuaEnv env = new LuaEnv();
        env.DoString("require'CSharpCallLua'");

        Add add = env.Global.Get<Add>("add");
        //定义resa,resb
        int resa;   int resb;
        int res=add(12, 78,out resa,out resb); 
        print(res+"_"+resa + "_" + resb);
    }

    private void OnDisable()
    {
        if (env != null)
        {
            env.Dispose();
            env = null;
        }
    }
}

输出结果:

方法2:映射到LuaFuntion

执行慢 ,不推荐

cs 复制代码
using System;
using UnityEngine;
using XLua;

public class CSharpCallLua : MonoBehaviour
{
    public LuaEnv env = null;

    void Start()
    {
        LuaEnv env = new LuaEnv();
        env.DoString("require'CSharpCallLua'");

        //方法2:映射到LuaFuntion
        LuaFunction func = env.Global.Get<LuaFunction>("add");
        object[] os= func.Call(1, 2);  //因为有多个返回值定义为object[]
        foreach (var o in os)
        {
         print(o);
        }
    }

    private void OnDisable()
    {
        if (env != null)
        {
            env.Dispose();
            env = null;
        }
    }
}

输出结果:

建议:

  • 不要重复的进行映射(Get)代价较大
  • 访问table 使用 interface(建议)
  • 访问function 使用 delegate (建议)
相关推荐
SongYuLong的博客6 分钟前
C# WPF编程-RepeatButton
开发语言·c#·wpf
八股文领域大手子4 小时前
Redis Lua脚本实现令牌桶限流算法
java·数据库·redis·算法·junit·mybatis·lua
咩咩觉主6 小时前
Unity 使用Odin插件解决多层字典配置文件问题
unity·c#·游戏引擎
互联网搬砖老肖8 小时前
编程语言选择分析:C#、Rust、Go 与 TypeScript 编译器优化
golang·rust·c#
江沉晚呤时9 小时前
深入了解 C# 中的 LINQ:功能、语法与应用解析
c#·solr·.netcore·lucene
一只_程序媛10 小时前
【leetcode hot 100 208】实现Trie(前缀树)
算法·leetcode·c#
LF男男10 小时前
xLua_003 Lua访问C#
游戏·c#·lua
欲与宇语10 小时前
List附加对象
windows·c#·list
搬砖工程师Cola12 小时前
<C#> 详细介绍.net 三种依赖注入:AddTransient、AddScoped、AddSingleton 的区别
开发语言·c#·.net
画个逗号给明天"16 小时前
C#从入门到精通(1)
开发语言·c#