SoFunction
Updated on 2025-03-07

A detailed explanation of a design representation of C# generic methods in lua

Preface

When registering lua method, most solutions directly negate the generic method because it is difficult to express generics on the lua side, and the problem of function overloading of lua.

Function overloading problems can be solved through some special methods, and generic problems are the main problems, in the case of Unity + Slua

For example, the following class:

public class Foo
  {
   public static void GetTypeName( type)
   {
    ();
   }
   public static void GetTypeName<T>()
   {
    (typeof(T).Name);
   }
  }

Generally only generatesGetTypeName( type)Registration method.

So how should a generic method be registered in Lua so that this call can be implemented? Generally speaking, when we call a generic method, we must be sure when writing code, like this:

&lt;int&gt;();// Output Int32

Lua cannot be constrained like this. Its call must be non-generic. This is the first question, and the second question is how to write lua? We hope that its writing can be maintained with C#

Consistent or similar, it makes people look easy to understand, but the brackets in lua are greater than or less, so you can't write this way. I wonder if there is any way

Because there is no type in lua, the type must come from C#, so generics can only be used as non-generic methods. If you let the function degrade and encapsulate it once, like the following

-- Put it firstCThe typeof of # is registered as a global function, and the registration system.Int32 is named intlocal Foo = {}
 = function(type)
 return function() 
  print()
 end
end
(typeof(int))();-- lua
<typeof(int)>();// C#

If you write this way, except for angle brackets, the two sides can basically be consistent, right? The operation result is the same

/*As for how to register typeof(int)*/
// Register a global function in LuaState's Init [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]internal static int getType(IntPtr L)
{
 type = null;
(L, 1, out type);
(L, type);
return 1;
}
// existLuaStateofInitRegister yourselfLuaDLL.lua_pushcfunction(L, getType);LuaDLL.lua_setglobal(L, "typeof");
// Add type alias toadd(typeof(System.Int32), "int"); // int

But the lua function here does not make calls from C#. Next, let’s see if there is any way to implement the call.

If it is automatically registered, Foo should be a registered type.

[]
public class Foo

And there is a meta table, and there is a non-generic GetTypeName method in the meta table. Don't touch the meta table now,

Register this directly into the Table, because if there are values ​​in the Table, you will not query the meta table.

import "Foo";
(typeof(int));// Output Int32
rawset(Foo, "GetTypeName", function(type)
 return function()
  local mt = getmetatable(Foo)
  local func = rawget(mt,"GetTypeName");
  func(type)
 end
end)

(typeof(int))();// Output Int32 -- Note that it has returnedfunctionThen call again

This method is rather rogue, because it directly defaults to non-generic functions and overwrites non-generic methods of meta tables, which is not desirable.

To continue, let’s first look at how a generic method is called through the Type method:

var methods = typeof(Foo).GetMethods( |  | );
  foreach(var method in methods)
  {
   if()
   {
    var paramters = ();
    if(paramters == null ||  == 0)
    {
     var genericMethod = (new Type[] { typeof(int) });
     if(genericMethod != null)
     {
      (null, null);// Output Int32break; }    }
   }
  }

Of course it is reflection, which can degenerate the generic method into non-generics. Although it is a slow reflection, the time is basically spent on Invoke, and there is not a big problem.

The remaining problem is overloading, there are two functions with the same name that are non-generic and generic. For testing, I first delete the non-generic.

[]
public class Foo
{
 //public static void GetTypeName( type)
 //{
 // ();
 //}
 public static void GetTypeName<T>()
 {
  (typeof(T).Name);
 }
}

The generated lua registration code needs to be modified as well

    a1;
   checkType(l,1,out a1);
   (a1);  // It's finished   pushValue(l,true);

Change to

 a1;
   checkType(l,1,out a1);
   var methods = typeof(Foo).GetMethods(.  
    |  
    | );
   foreach(var method in methods)
   {
    if()
    {
     var paramters = ();
     if(paramters == null ||  == 0)
     {
      var genericMethod = (new Type[] { typeof(int) });
      if(genericMethod != null)
      {
       (null, null);
       break;
      }
     }
    }
   }
   pushValue(l,true);

Try running it and see. It seems that there is no problem with the output Int32. The problem is that it still needs to be manually encapsulated on Lua:

rawset(Foo, "GetTypeName", function(type)
 local mt = getmetatable(Foo)
 local func = rawget(mt,"GetTypeName");
 func(type)
end)
-- The problem is, Not performed oncerawsetCan't get generic writing
(typeof(int));// Output Int32 -- Tablemethod

At this point, you can basically draw a conclusion.

1. In lua, you can get close to the writing of C# generics by encapsulation (closure), the difference is just a bracket and a bracket

(typeof(int))();-- lua
<typeof(int)>();// C#

However, the process is extremely complex. For example, the rawset process in the above code needs to be implemented in the registration code of C#, but it needs to be reflected in the call location, and the problem of function overloading needs to be solved on the lua side.

The above example is directly overridden. Non-generic method functions cannot be accessed normally.

2. Since generic methods can be degenerated into non-generics, you can directly detect whether there are non-generic functions with the same name and the same parameters. If not, add the non-generic version of the generic method to the registered function.

Summarize

The above is the entire content of this article. I hope that the content of this article has certain reference value for your study or work. Thank you for your support.