Unverified Commit 190a8505 authored by Vinicius Jarina's avatar Vinicius Jarina Committed by GitHub
Browse files

Avoid call GetExtensionMethod twice. (#279)

* Avoid call GetExtensionMethod twice.

* `LuaMethodWrapper.Call` cleanup.
parent 10e392a0
......@@ -311,8 +311,7 @@ namespace NLua
{
if (!luaState.IsString(stackPos))
return null;
string retVal = luaState.ToString(stackPos, false);
return retVal;
return luaState.ToString(stackPos, false);
}
private object GetAsTable(LuaState luaState, int stackPos)
......@@ -354,10 +353,12 @@ namespace NLua
{
object obj = _translator.GetNetObject(luaState, stackPos);
if (obj == null && luaState.Type(stackPos) == LuaType.Table)
{
if (luaState.GetMetaField(stackPos, "__index") != LuaType.Nil)
{
if (obj != null || luaState.Type(stackPos) != LuaType.Table)
return obj;
if (luaState.GetMetaField(stackPos, "__index") == LuaType.Nil)
return null;
if (luaState.CheckMetaTable(-1, _translator.Tag))
{
luaState.Insert(stackPos);
......@@ -366,8 +367,6 @@ namespace NLua
}
else
luaState.SetTop(-2);
}
}
return obj;
}
......
......@@ -30,6 +30,7 @@ namespace NLua.Extensions
luaState.RawGetInteger(LuaRegistry.Index, reference);
}
// ReSharper disable once IdentifierTypo
public static void Unref (this LuaState luaState, int reference)
{
luaState.Unref(LuaRegistry.Index, reference);
......
......@@ -47,25 +47,21 @@ namespace NLua
/// <summary>
/// True while a script is being executed
/// </summary>
public bool IsExecuting => executing;
public bool IsExecuting => _executing;
public LuaState State => _luaState;
private ObjectTranslator _translator;
/// <summary>
/// Used to protect the (global) object translator pool during add/remove
/// </summary>
private static readonly object translatorPoolLock = new object();
/// <summary>
/// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects
/// </summary>
//private object luaLock = new object();
private bool _StatePassed;
private bool executing;
private bool _executing;
// The commented code bellow is the initLua, the code assigned here is minified for size/performance reasons.
private static string initLuanet = @"local a={}local rawget=rawget;local b=luanet.import_type;local c=luanet.load_assembly;luanet.error,luanet.type=error,type;function a:__index(d)local e=rawget(self,'.fqn')e=(e and e..'.'or'')..d;local f=rawget(luanet,d)or b(e)if f==nil then pcall(c,e)f={['.fqn']=e}setmetatable(f,a)end;rawset(self,d,f)return f end;function a:__call(...)error('No such type: '..rawget(self,'.fqn'),2)end;luanet['.fqn']=false;setmetatable(luanet,a)luanet.load_assembly('mscorlib')";
private const string InitLuanet = @"local a={}local rawget=rawget;local b=luanet.import_type;local c=luanet.load_assembly;luanet.error,luanet.type=error,type;function a:__index(d)local e=rawget(self,'.fqn')e=(e and e..'.'or'')..d;local f=rawget(luanet,d)or b(e)if f==nil then pcall(c,e)f={['.fqn']=e}setmetatable(f,a)end;rawset(self,d,f)return f end;function a:__call(...)error('No such type: '..rawget(self,'.fqn'),2)end;luanet['.fqn']=false;setmetatable(luanet,a)luanet.load_assembly('mscorlib')";
//@"local metatable = {}
// local rawget = rawget
// local import_type = luanet.import_type
......@@ -106,7 +102,7 @@ namespace NLua
// -- Preload the mscorlib assembly
// luanet.load_assembly('mscorlib')";
private static string clr_package = @"if not luanet then require'luanet'end;local a,b=luanet.import_type,luanet.load_assembly;local c={__index=function(d,e)local f=rawget(d,e)if f==nil then f=a(d.packageName.."".""..e)if f==nil then f=a(e)end;d[e]=f end;return f end}function luanet.namespace(g)if type(g)=='table'then local h={}for i=1,#g do h[i]=luanet.namespace(g[i])end;return unpack(h)end;local j={packageName=g}setmetatable(j,c)return j end;local k,l;local function m()l={}k={__index=function(n,e)for i,d in ipairs(l)do local f=d[e]if f then _G[e]=f;return f end end end}setmetatable(_G,k)end;function CLRPackage(o,p)p=p or o;local q=pcall(b,o)return luanet.namespace(p)end;function import(o,p)if not k then m()end;if not p then local i=o:find('%.dll$')if i then p=o:sub(1,i-1)else p=o end end;local j=CLRPackage(o,p)table.insert(l,j)return j end;function luanet.make_array(r,s)local t=r[#s]for i,u in ipairs(s)do t:SetValue(u,i-1)end;return t end;function luanet.each(v)local w=v:GetEnumerator()return function()if w:MoveNext()then return w.Current end end end";
private const string ClrPackage = @"if not luanet then require'luanet'end;local a,b=luanet.import_type,luanet.load_assembly;local c={__index=function(d,e)local f=rawget(d,e)if f==nil then f=a(d.packageName.."".""..e)if f==nil then f=a(e)end;d[e]=f end;return f end}function luanet.namespace(g)if type(g)=='table'then local h={}for i=1,#g do h[i]=luanet.namespace(g[i])end;return unpack(h)end;local j={packageName=g}setmetatable(j,c)return j end;local k,l;local function m()l={}k={__index=function(n,e)for i,d in ipairs(l)do local f=d[e]if f then _G[e]=f;return f end end end}setmetatable(_G,k)end;function CLRPackage(o,p)p=p or o;local q=pcall(b,o)return luanet.namespace(p)end;function import(o,p)if not k then m()end;if not p then local i=o:find('%.dll$')if i then p=o:sub(1,i-1)else p=o end end;local j=CLRPackage(o,p)table.insert(l,j)return j end;function luanet.make_array(r,s)local t=r[#s]for i,u in ipairs(s)do t:SetValue(u,i-1)end;return t end;function luanet.each(v)local w=v:GetEnumerator()return function()if w:MoveNext()then return w.Current end end end";
//@"---
//--- This lua module provides auto importing of .net classes into a named package.
//--- Makes for super easy use of LuaInterface glue
......@@ -282,12 +278,11 @@ namespace NLua
_luaState.SetTable(-3);
_luaState.PopGlobalTable();
_translator = new ObjectTranslator(this, _luaState);
lock (translatorPoolLock)
{
ObjectTranslatorPool.Instance.Add(_luaState, _translator);
}
_luaState.PopGlobalTable();
_luaState.DoString(initLuanet);
_luaState.DoString(InitLuanet);
}
public void Close()
......@@ -295,13 +290,10 @@ namespace NLua
if (_StatePassed || _luaState == null)
return;
lock (translatorPoolLock)
{
_luaState.Close();
ObjectTranslatorPool.Instance.Remove(_luaState);
_luaState = null;
}
}
#if __IOS__ || __TVOS__ || __WATCHOS__
[MonoPInvokeCallback(typeof(LuaNativeFunction))]
......@@ -388,7 +380,7 @@ namespace NLua
public LuaFunction LoadString(string chunk, string name)
{
int oldTop = _luaState.GetTop();
executing = true;
_executing = true;
try
{
......@@ -397,7 +389,7 @@ namespace NLua
}
finally
{
executing = false;
_executing = false;
}
var result = _translator.GetFunction(_luaState, -1);
......@@ -414,7 +406,7 @@ namespace NLua
public LuaFunction LoadString(byte[] chunk, string name)
{
int oldTop = _luaState.GetTop();
executing = true;
_executing = true;
try
{
......@@ -423,7 +415,7 @@ namespace NLua
}
finally
{
executing = false;
_executing = false;
}
var result = _translator.GetFunction(_luaState, -1);
......@@ -457,7 +449,7 @@ namespace NLua
public object[] DoString(byte[] chunk, string chunkName = "chunk")
{
int oldTop = _luaState.GetTop();
executing = true;
_executing = true;
if (_luaState.LoadBuffer(chunk, chunkName) != LuaStatus.OK)
ThrowExceptionFromError(oldTop);
......@@ -479,7 +471,7 @@ namespace NLua
}
finally
{
executing = false;
_executing = false;
}
}
......@@ -492,7 +484,7 @@ namespace NLua
public object[] DoString(string chunk, string chunkName = "chunk")
{
int oldTop = _luaState.GetTop();
executing = true;
_executing = true;
if (_luaState.LoadString(chunk, chunkName) != LuaStatus.OK)
ThrowExceptionFromError(oldTop);
......@@ -514,7 +506,7 @@ namespace NLua
}
finally
{
executing = false;
_executing = false;
}
}
......@@ -529,7 +521,7 @@ namespace NLua
if (_luaState.LoadFile(fileName) != LuaStatus.OK)
ThrowExceptionFromError(oldTop);
executing = true;
_executing = true;
int errorFunctionIndex = 0;
if (UseTraceback)
......@@ -547,7 +539,7 @@ namespace NLua
}
finally
{
executing = false;
_executing = false;
}
}
......@@ -776,9 +768,10 @@ namespace NLua
CodeGeneration.Instance.RegisterLuaClassType(klass, luaClass);
}
// ReSharper disable once InconsistentNaming
public void LoadCLRPackage()
{
_luaState.DoString(clr_package);
_luaState.DoString(ClrPackage);
}
/*
* Gets a function global variable as a delegate of
......@@ -821,7 +814,7 @@ namespace NLua
_translator.Push(_luaState, args[i]);
}
executing = true;
_executing = true;
try
{
......@@ -838,7 +831,7 @@ namespace NLua
}
finally
{
executing = false;
_executing = false;
}
if (returnTypes != null)
......@@ -934,7 +927,7 @@ namespace NLua
{
if (_hookCallback == null)
{
_hookCallback = new LuaHookFunction(Lua.DebugHookCallback);
_hookCallback = DebugHookCallback;
_luaState.SetHook(_hookCallback, mask, count);
}
......@@ -1164,7 +1157,7 @@ namespace NLua
_luaState.SetTop(oldTop);
}
public LuaFunction RegisterFunction(string path, MethodBase function /*MethodInfo function*/)
public LuaFunction RegisterFunction(string path, MethodBase function)
{
return RegisterFunction(path, null, function);
}
......@@ -1173,7 +1166,7 @@ namespace NLua
* Registers an object's method as a Lua function (global or table field)
* The method may have any signature
*/
public LuaFunction RegisterFunction(string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id = 2859&forum_id = 145)
public LuaFunction RegisterFunction(string path, object target, MethodBase function)
{
// We leave nothing on the stack when we are done
int oldTop = _luaState.GetTop();
......@@ -1198,6 +1191,7 @@ namespace NLua
return equal;
}
// ReSharper disable once InconsistentNaming
internal void PushCSFunction(LuaNativeFunction function)
{
_translator.PushFunction(_luaState, function);
......
This diff is collapsed.
......@@ -34,7 +34,7 @@ namespace NLua.Method
readonly string _methodName;
readonly MethodInfo[] _members;
MethodCache _lastCalledMethod;
private MethodCache _lastCalledMethod;
/*
......@@ -46,10 +46,12 @@ namespace NLua.Method
_translator = translator;
_target = target;
_extractTarget = translator.typeChecker.GetExtractor(targetType);
_lastCalledMethod = new MethodCache();
_method = method;
_methodName = method.Name;
_isStatic = method.IsStatic;
}
/*
......@@ -62,6 +64,7 @@ namespace NLua.Method
_translator = translator;
_methodName = methodName;
_extractTarget = translator.typeChecker.GetExtractor(targetType);
_lastCalledMethod = new MethodCache();
_isStatic = (bindingType & BindingFlags.Static) == BindingFlags.Static;
_members = GetMethodsRecursively(targetType.UnderlyingSystemType,
......@@ -90,48 +93,11 @@ namespace NLua.Method
return _translator.interpreter.SetPendingException(e);
}
/*
* Calls the method. Receives the arguments from the Lua stack
* and returns values in it.
*/
int Call(IntPtr state)
void FillMethodArguments(LuaState luaState, int numStackToSkip)
{
var luaState = LuaState.FromIntPtr(state);
MethodBase methodToCall = _method;
object targetObject = _target;
bool failedCall = true;
int nReturnValues = 0;
if (!luaState.CheckStack(5))
throw new LuaException("Lua stack overflow");
bool isStatic = _isStatic;
SetPendingException(null);
if (methodToCall == null)
{ // Method from name
if (isStatic)
targetObject = null;
else
targetObject = _extractTarget(luaState, 1);
if (_lastCalledMethod.cachedMethod != null)
{ // Cached?
int numStackToSkip = isStatic ? 0 : 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject
int numArgsPassed = luaState.GetTop() - numStackToSkip;
MethodBase method = _lastCalledMethod.cachedMethod;
if (numArgsPassed == _lastCalledMethod.argTypes.Length)
{ // No. of args match?
if (!luaState.CheckStack(_lastCalledMethod.outList.Length + 6))
throw new LuaException("Lua stack overflow");
object[] args = _lastCalledMethod.args;
try
{
for (int i = 0; i < _lastCalledMethod.argTypes.Length; i++)
{
MethodArgs type = _lastCalledMethod.argTypes[i];
......@@ -142,7 +108,7 @@ namespace NLua.Method
if (_lastCalledMethod.argTypes[i].IsParamsArray)
{
int count = _lastCalledMethod.argTypes.Length - i;
Array paramArray = _translator.TableToArray(luaState, type.ExtractValue, type.ParamsArrayType, index, count);
Array paramArray = _translator.TableToArray(luaState, type.ExtractValue, type.ParameterType, index, count);
args[_lastCalledMethod.argTypes[i].Index] = paramArray;
}
else
......@@ -154,44 +120,102 @@ namespace NLua.Method
!luaState.IsNil(i + 1 + numStackToSkip))
throw new LuaException(string.Format("Argument number {0} is invalid", (i + 1)));
}
}
if (_isStatic)
_translator.Push(luaState, method.Invoke(null, _lastCalledMethod.args));
else
int PushReturnValue(LuaState luaState)
{
int nReturnValues = 0;
// Pushes out and ref return values
for (int index = 0; index < _lastCalledMethod.outList.Length; index++)
{
nReturnValues++;
_translator.Push(luaState, _lastCalledMethod.args[_lastCalledMethod.outList[index]]);
}
// If not return void,we need add 1,
// or we will lost the function's return value
// when call dotnet function like "int foo(arg1,out arg2,out arg3)" in Lua code
if (!_lastCalledMethod.IsReturnVoid && nReturnValues > 0)
nReturnValues++;
return nReturnValues < 1 ? 1 : nReturnValues;
}
int CallInvoke(LuaState luaState, MethodBase method, object targetObject)
{
if (!luaState.CheckStack(_lastCalledMethod.outList.Length + 6))
throw new LuaException("Lua stack overflow");
try
{
if (method.IsConstructor)
_translator.Push(luaState, ((ConstructorInfo)method).Invoke(_lastCalledMethod.args));
else
_translator.Push(luaState, method.Invoke(targetObject, _lastCalledMethod.args));
}
failedCall = false;
}
catch (TargetInvocationException e)
{
// Failure of method invocation
if (_translator.interpreter.UseTraceback) e.GetBaseException().Data["Traceback"] = _translator.interpreter.GetDebugTraceback();
if (_translator.interpreter.UseTraceback)
e.GetBaseException().Data["Traceback"] = _translator.interpreter.GetDebugTraceback();
return SetPendingException(e.GetBaseException());
}
catch (Exception e)
{
if (_members.Length == 1) // Is the method overloaded?
// No, throw error
return SetPendingException(e);
}
return PushReturnValue(luaState);
}
bool IsMethodCached(LuaState luaState, int numArgsPassed, int skipParams)
{
if (_lastCalledMethod.cachedMethod == null)
return false;
if (numArgsPassed != _lastCalledMethod.argTypes.Length)
return false;
// If there is no method overloads, is ok to use the cached method
if (_members.Length == 1)
return true;
return _translator.MatchParameters(luaState, _lastCalledMethod.cachedMethod, _lastCalledMethod, skipParams);
}
// Cache miss
if (failedCall)
int CallMethodFromName(LuaState luaState)
{
// System.Diagnostics.Debug.WriteLine("cache miss on " + methodName);
object targetObject = null;
if (!_isStatic)
targetObject = _extractTarget(luaState, 1);
int numStackToSkip =
_isStatic
? 0
: 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject
int numArgsPassed = luaState.GetTop() - numStackToSkip;
// Cached?
if (IsMethodCached(luaState, numArgsPassed, numStackToSkip))
{
MethodBase method = _lastCalledMethod.cachedMethod;
if (!luaState.CheckStack(_lastCalledMethod.outList.Length + 6))
throw new LuaException("Lua stack overflow");
FillMethodArguments(luaState, numStackToSkip);
return CallInvoke(luaState, method, targetObject);
}
// If we are running an instance variable, we can now pop the targetObject from the stack
if (!isStatic)
if (!_isStatic)
{
if (targetObject == null)
{
_translator.ThrowError(luaState, string.Format("instance method '{0}' requires a non null target object", _methodName));
_translator.ThrowError(luaState,
string.Format("instance method '{0}' requires a non null target object", _methodName));
luaState.PushNil();
return 1;
}
......@@ -204,8 +228,11 @@ namespace NLua.Method
foreach (var member in _members)
{
if (member.ReflectedType == null)
continue;
candidateName = member.ReflectedType.Name + "." + member.Name;
bool isMethod = _translator.MatchParameters(luaState, member, ref _lastCalledMethod);
bool isMethod = _translator.MatchParameters(luaState, member, _lastCalledMethod, 0);
if (isMethod)
{
......@@ -216,39 +243,56 @@ namespace NLua.Method
if (!hasMatch)
{
string msg = (candidateName == null) ? "Invalid arguments to method call" : ("Invalid arguments to method: " + candidateName);
string msg = (candidateName == null)
? "Invalid arguments to method call"
: ("Invalid arguments to method: " + candidateName);
_translator.ThrowError(luaState, msg);
luaState.PushNil();
return 1;
}
return CallInvoke(luaState, _lastCalledMethod.cachedMethod, targetObject);
}
}
else
{ // Method from MethodBase instance
if (methodToCall.ContainsGenericParameters)
{
_translator.MatchParameters(luaState, methodToCall, ref _lastCalledMethod);
if (methodToCall.IsGenericMethodDefinition)
int CallInvokeOnGenericMethod(LuaState luaState, MethodInfo methodToCall, object targetObject)
{
_translator.MatchParameters(luaState, methodToCall, _lastCalledMethod, 0);
//need to make a concrete type of the generic method definition
var typeArgs = new List<Type>();
foreach (object arg in _lastCalledMethod.args)
typeArgs.Add(arg.GetType());
var concreteMethod = ((MethodInfo)methodToCall).MakeGenericMethod(typeArgs.ToArray());
var concreteMethod = methodToCall.MakeGenericMethod(typeArgs.ToArray());
_translator.Push(luaState, concreteMethod.Invoke(targetObject, _lastCalledMethod.args));
failedCall = false;
return PushReturnValue(luaState);
}
else if (methodToCall.ContainsGenericParameters)
/*
* Calls the method. Receives the arguments from the Lua stack
* and returns values in it.
*/
int Call(IntPtr state)
{
_translator.ThrowError(luaState, "Unable to invoke method on generic class as the current method is an open generic method");
luaState.PushNil();
return 1;
}
}
else
var luaState = LuaState.FromIntPtr(state);
MethodBase methodToCall = _method;
object targetObject = _target;
if (!luaState.CheckStack(5))
throw new LuaException("Lua stack overflow");
SetPendingException(null);
// Method from name
if (methodToCall == null)
return CallMethodFromName(luaState);
// Method from MethodBase instance
if (!methodToCall.ContainsGenericParameters)
{
if (!methodToCall.IsStatic && !methodToCall.IsConstructor && targetObject == null)
{
......@@ -256,58 +300,30 @@ namespace NLua.Method
luaState.Remove(1); // Pops the receiver
}
if (!_translator.MatchParameters(luaState, methodToCall, ref _lastCalledMethod))
if (!_translator.MatchParameters(luaState, methodToCall, _lastCalledMethod, 0))
{
_translator.ThrowError(luaState, "Invalid arguments to method call");
luaState.PushNil();
return 1;
}
}
}
if (failedCall)
{
if (!luaState.CheckStack(_lastCalledMethod.outList.Length + 6))
throw new LuaException("Lua stack overflow");
try
{
if (isStatic)
_translator.Push(luaState, _lastCalledMethod.cachedMethod.Invoke(null, _lastCalledMethod.args));
else
{
if (_lastCalledMethod.cachedMethod.IsConstructor)
_translator.Push(luaState, ((ConstructorInfo)_lastCalledMethod.cachedMethod).Invoke(_lastCalledMethod.args));
else
_translator.Push(luaState, _lastCalledMethod.cachedMethod.Invoke(targetObject, _lastCalledMethod.args));
}
}
catch (TargetInvocationException e)
{
if (_translator.interpreter.UseTraceback) e.GetBaseException().Data["Traceback"] = _translator.interpreter.GetDebugTraceback();
return SetPendingException(e.GetBaseException());
}
catch (Exception e)
if (!methodToCall.IsGenericMethodDefinition)
{
return SetPendingException(e);
}
_translator.ThrowError(luaState,
"Unable to invoke method on generic class as the current method is an open generic method");
luaState.PushNil();
return 1;
}
// Pushes out and ref return values
for (int index = 0; index < _lastCalledMethod.outList.Length; index++)
{
nReturnValues++;
_translator.Push(luaState, _lastCalledMethod.args[_lastCalledMethod.outList[index]]);
return CallInvokeOnGenericMethod(luaState, (MethodInfo) methodToCall, targetObject);
}
if (_isStatic)
targetObject = null;
// If not return void,we need add 1,
// or we will lost the function's return value
// when call dotnet function like "int foo(arg1,out arg2,out arg3)" in Lua code
if (!_lastCalledMethod.IsReturnVoid && nReturnValues > 0)
nReturnValues++;
return nReturnValues < 1 ? 1 : nReturnValues;
return CallInvoke(luaState, _lastCalledMethod.cachedMethod, targetObject);
}
}
}
\ No newline at end of file
......@@ -5,13 +5,14 @@ namespace NLua.Method
/*
* Parameter information
*/
struct MethodArgs
class MethodArgs
{
// Position of parameter
public int Index;
public Type ParameterType;
// Type-conversion function
public ExtractValue ExtractValue;
public bool IsParamsArray;
public Type ParamsArrayType;
}
}
\ No newline at end of file
......@@ -4,8 +4,14 @@ using NLua.Extensions;
namespace NLua.Method
{
struct MethodCache
class MethodCache
{
public MethodCache()
{
args = new object[0];
argTypes = new MethodArgs[0];
outList = new int[0];
}
private MethodBase _cachedMethod;
public MethodBase cachedMethod {
......
......@@ -331,9 +331,10 @@ namespace NLua
return null;
}
public bool IsExtensionMethodPresent(Type type, string name)
public bool TryGetExtensionMethod(Type type, string name, out MethodInfo method)
{
return GetExtensionMethod(type, name) != null;
method = GetExtensionMethod(type, name);
return method != null;
}
public MethodInfo GetExtensionMethod(Type type, string name)
......@@ -1009,9 +1010,9 @@ namespace NLua
* Checks if the method matches the arguments in the Lua stack, getting
* the arguments if it does.
*/
internal bool MatchParameters(LuaState luaState, MethodBase method, ref MethodCache methodCache)
internal bool MatchParameters(LuaState luaState, MethodBase method, MethodCache methodCache, int skipParam)
{
return metaFunctions.MatchParameters(luaState, method, ref methodCache);
return metaFunctions.MatchParameters(luaState, method, methodCache, skipParam);
}
internal Array TableToArray(LuaState luaState, ExtractValue extractValue, Type paramArrayType, int startIndex, int count)
......
......@@ -188,8 +188,11 @@ namespace NLuaTest
lua.DoString("test=TestClass()");
lua.DoString("test:MethodOverload()");
lua.DoString("test:MethodOverload(test)");
lua.DoString("test:MethodOverload(test)");
lua.DoString("test:MethodOverload(1,1,1)");
lua.DoString("test:MethodOverload(2,2,i)\r\nprint(i)");
lua.DoString("i = test:MethodOverload(2,2)\r\nprint(i)");
int i = (int) lua.GetNumber("i");
Assert.AreEqual(5, i, "#1");
}
}
......@@ -1677,7 +1680,7 @@ namespace NLuaTest
lua.DoString("test=TestClass()");
lua.DoString("setMethod=luanet.get_method_bysig(TestClass,'setVal','System.String')");
lua.DoString("setMethod(test,'test')");
TestTypes.TestClass test = (TestTypes.TestClass)lua["test"];
var test = (TestTypes.TestClass)lua["test"];
Assert.AreEqual("test", test.getStrVal());
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment