[XLua热更新] Lua调用C#

1,003 阅读6分钟

XLua热更新三部曲

一、lua访问C#静态属性与方法

  • 基本规则
    • lua里头没有new关键字。
    • 所有C#相关的都放到CS下,包括构造函数,静态成员属性、方法。
-- 1.实例化一个Unity对象
-- 等价的unity 代码: GameObject newGo = new GameObject();
local newGo = CS.UnityEngine.GameObject()  -- unity 中多了一个newGo的空物体


--2. lua查找游戏物体,改名
local TexBeg = CS.UnityEngine.GameObject.Find("TexBeg") --在unity中查找名字为"TexBeg"的物体
TexBeg.name = "Begin" --把TexBeg 改名为 Begin

local TexStart = TexBeg:GetComponent("UnityEngine.UI.Text")
TexStart.text = "修改为Start" --把TexBeg的文本 改名为"修改为Start"

二、lua访问C#常用方式

调用自定义c#类

local IsInvoke = CS.IsInvokedClass -- 找到IsInvokedClass类

local classObj = IsInvoke() -- 调用父类和子类的构造函数
-- 输出:先后调用父类和子类的构造函数
--  IsInvokedClass是父类构造函数
--  IsInvokedClass是子类构造函数
 

访问成员属性与方法

方式用法
读成员属性classobj.DMF
写成员属性classobj.DMF = 1024
调用成员方法classobj:DMFunc()

注意:

  • lua中使用冒号,表示成员方法的调用。它自动完成把当前对象作为一 个参数,传入方法。
  • lua中使用点,则表示静态属性与方法调用。它需要手工往方法中传递 当前对象。
--4.调用普通方法
classObj:Method1() --子类方法
classObj:ShowFatherInfo() -- 父类方法

--5.调用重载方法
---lua的类型远远不如C#丰富,存在一对多的情况
---比如C#的int,float,double都对应于lua的number。只能调用到其中一个(生成代码中排前面的那个)
classObj:Method1(1,2)
classObj:Method1("你好","再见")

--6.调用c#中带有params关键字的方法
local res = classObj:Method2(10,20,"a","b","c","qwe","rrr")
print("调用c#中带有params关键字的方法,返回值 = "..res);
-- 输出:调用c#中带有params关键字的方法,返回值 = 30

--7.Lua 映射c#结构体及接口参数
--- 调用结构体
myStruct = {x = "apple", y = "banana"}
classObj:Method3(myStruct) -- 传入结构体
-- 输出:p.x = apple  p.y = banana


---调用接口
myInterface = {
    x = 1000,
    y = 800,
    speak = function()
        print("Lua中speak方法调用")
    end
}
classObj:Method4(myInterface)-- 传入接口
-- 输出:p.x p.x = 1000 p.y = 800


--8.Lua 映射c#委托
---num是从c#中获取的“88”,调用是通过lua调用
myDelegate = function(num)
    print("Lua 映射委托的方法,参数为"..num)
end
classObj:Method5(myDelegate)
--输出: LUA: Lua 映射委托的方法,参数为88


--9.LUA 调用多返回值的方法
/* c#代码

*/
local num1 = 10
local num2 = 20
local num3 = 30
local res1,res2,res3 = classObj:Method6(num1,num2,num3)
print("res1 "..res1)
print("res2 "..res2)
print("res3 "..res3)

调用泛型为参数的方法

/* c#代码
    public void Method7(List<string> strArray)
    {
        Debug.Log("定义一个泛型为参数的方法");
        foreach(var item in strArray)
         {
            Debug.Log("泛型集合: " + item);
         }
    }
*/
mytable = {"apple","banana","peach","pear"}
classObj:Method7(mytable)
-- 输出:所有mytable元素

---C#调用自定义泛型方法
classObj:Method_InvokeGen()

---C#调用扩展方法
classObj:Method_InvokeGenExtensionGen()

--lua传参: 拓展方法才能传参数。原方法会报错
maxNum = CS.MyGengerric():ExtGetMax(888,666)
print("用扩展方法传参数"..maxNum)

附录

LuaScripts.Lua (调用脚本)

--- Lua调用unity系统的api

--1.实例化一个Unity对象
--对应unity: GameObject newGo = new GameObject();
local newGo = CS.UnityEngine.GameObject() -- unity 中多了一个newGo的空物体


--2. 查找游戏物体,改名
local TexBeg = CS.UnityEngine.GameObject.Find("TexBeg")
TexBeg.name = "Begin" --把TexBeg 改名为 Begin

local TexStart = TexBeg:GetComponent("UnityEngine.UI.Text")
TexStart.text = "修改为Start" --把TexBeg的文本 改名为"修改为Start"

--3. 调用自定义c#类
local IsInvoke = CS.IsInvokedClass -- 找到IsInvokedClass类

local classObj = IsInvoke() -- 调用父类和子类的构造函数

--4.调用普通方法
classObj:Method1() --子类方法
classObj:ShowFatherInfo() -- 父类方法

--5.调用重载方法
---lua的类型远远不如C#丰富,存在一对多的情况
---比如C#的int,float,double都对应于lua的number。只能调用到其中一个(生成代码中排前面的那个)
classObj:Method1(1,2)
classObj:Method1("你好","再见")

--6.调用c#中带有params关键字的方法
local res = classObj:Method2(10,20,"a","b","c","qwe","rrr")
print("调用c#中带有params关键字的方法,返回值 = "..res);

--7.Lua 映射c#结构体及接口参数
--- 调用结构体
myStruct = {x = "apple", y = "banana"}
classObj:Method3(myStruct) -- 传入结构体

---调用接口
myInterface = {
    x = 1000,
    y = 800,
    speak = function()
        print("Lua中speak方法调用")
    end
}
classObj:Method4(myInterface)-- 传入接口


--8.Lua 映射c#委托
---num是从c#中获取的“88”,调用是通过lua调用
myDelegate = function(num)
    print("Lua 映射委托的方法,参数为"..num)
end
classObj:Method5(myDelegate)

--9.LUA 调用多返回值的方法
local num1 = 10
local num2 = 20
local num3 = 30
local res1,res2,res3 = classObj:Method6(num1,num2,num3)
print("res1 "..res1)
print("res2 "..res2)
print("res3 "..res3)

--10.定义一个泛型为参数的方法
mytable = {"apple","banana","peach","pear"}
classObj:Method7(mytable)

---C#调用自定义泛型方法
classObj:Method_InvokeGen()

---C#调用扩展方法
classObj:Method_InvokeGenExtensionGen()

--拓展方法才能传参数。原方法会报错
maxNum = CS.MyGengerric():ExtGetMax(888,666)
print("用扩展方法传参数"..maxNum)

IsInvokedClass.CS(lua主要调用的类)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using XLua.LuaDLL;


public class IsInvokedClass : IsInvoked_Father
{
     public  string ChildClassName = " 子类字段";

     public IsInvokedClass()
     {
        Debug.Log(" IsInvokedClass是子类构造函数");
     }

    //重载方法
    public void Method1()
    {
            Debug.Log(" IsInvokedClass子类的Method1方法");
    }

    public void Method1(int num1, int num2)
    {
        Debug.Log(" Method1(int num1, int num2):" + num1 + num2);
    }

    public void Method1(string  num1, string  num2)
    {
        Debug.Log(" Method1(string  num1, string  num2):" + num1 + num2);
    }

    //6.定义带有返回值,参数,params关键字的方法
    public int Method2(int num1, int num2, params string[] strArray)
    {
        Debug.Log("带params关键字的方法");
        foreach(string item in strArray)
        {
            Debug.Log("输出参数内容:" + item);
        }
        return num1 + num2;
    }

    //7.Lua 映射c#结构体
    public void Method3(MyStruct p)
    {
        Debug.Log("Lua 映射c#结构体");
        Debug.Log("p.x = " + p.x + "p.y = " + p.y);
    }
    //7.Lua 映射c#接口参数
    public void Method4(MyInterface p)
    {
        Debug.Log("6.Lua 映射c#接口参数");
        Debug.Log("p.x = " + p.x + " p.y = " + p.y);
    }


    //8.Lua 映射c#委托
    public void Method5(MyDelegate p)
    {
        Debug.Log("8.Lua 映射c#委托");
        p.Invoke(88);
    }

    //9.LUA 调用多返回值的方法
    public int Method6(int num1, out int num2, ref int num3)
    {
        Debug.Log("9.LUA 调用多返回值的方法");
        num2 = 3000;
        num3 = 1000;
        return num1 + 100;
    }

    //10.定义一个泛型为参数的方法
    public void Method7(List<string> strArray)
    {
        Debug.Log("定义一个泛型为参数的方法");
        foreach(var item in strArray)
         {
            Debug.Log("泛型集合: " + item);
         }
    }

    //C#调用自定义泛型方法
    public void Method_InvokeGen()
    {
        int maxNum = 0;
        int num1 = 100;
        int num2 = 200;
        MyGengerric obj = new MyGengerric();
        maxNum = obj.GetMax<int>(num1, num2);
        Debug.Log("C#中比大小:" + maxNum);
    }
    //C#调用扩展方法
    public void Method_InvokeGenExtensionGen()
    {
         int maxNum = 0;
         int num1 = 600;
         int num2 = 800;
         MyGengerric obj = new MyGengerric();
         maxNum = obj.ExtGetMax(num1, num2);
         Debug.Log("C#中扩展方法比大小:" + maxNum);

    }

}

public struct MyStruct
{
    public string x, y;
}

[CSharpCallLua]
//调用接口,必须引用xlua包 + 打标签
public interface MyInterface
{
    int x { get; set; }
    int y { get; set; }
    void speak();
}

[CSharpCallLua]
//委托
public delegate void MyDelegate(int num);

IsInvoked_Father.cs(父类)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IsInvoked_Father
{
     public  string FatherClassName = " 父类字段";

     public IsInvoked_Father()
     {
        Debug.Log(" IsInvokedClass是父类构造函数");
     }

    public  void ShowFatherInfo()
    {
         Debug.Log(" IsInvoked_Father父类的ShowFatherInfo方法");
    }


}

MyGengerric.cs(自定义泛型)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyGengerric
{
     public T GetMax<T>(T num1, T num2) where T : IComparable
     {
          if(num1.CompareTo(num2) < 0)
          { return num2;}
          else
          {return num1;}
     }
}

Extention_myGene(定义拓展方法)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
//注意:是LuaCallCSharp,不是反过来的
[LuaCallCSharp]
// 定义拓展方法
public static class Extention_myGene
{
    //被拓展类作为第一个参数this MyGengerric gen
    //要加this
     public static int ExtGetMax(this MyGengerric gen, int num1, int num2)
     {
          if(num1 < num2)
         {
            return num2;
         }
        else
        {
            return num1;
        }
     }
}

HelloWorld.cs (调用lua函数)

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;

public class HelloWorld : MonoBehaviour
{
    LuaEnv env = null;

    // Start is called before the first frame update
    void Start()
    {
        env = new LuaEnv();
        env.AddLoader(HelloWorld.CustomMyLoader); // 调用方法
        env.DoString("require 'LuaScripts'");

    }

    public static byte[] CustomMyLoader(ref string fileName)
    {
        byte[] byArrayReture = null;
        //脚本的路径
        string luaPath = Application.dataPath + "/Scripts/LuaScripts/" + fileName + ".lua";
        //读取lua路径中指定的lua文件
        string strLuaContent = File.ReadAllText(luaPath);
        //数据类型转换
        byArrayReture = System.Text.Encoding.UTF8.GetBytes(strLuaContent);
        return byArrayReture;
    }

    private void OnDestroy()
    {
        //释放env
        env.Dispose();
    }
}