Commit 83fb7adc authored by Vinicius Jarina's avatar Vinicius Jarina
Browse files

Fixed `GetMethodFallback` to check `GetRuntimeMethods` and `TryGetValueForKey`.

parent c3b15c9b
......@@ -473,74 +473,141 @@ namespace NLua
return PushExtensionMethod(luaState, objType, obj, methodName, method);
}
// Try to use get_Item to index into this .net object
var methods = objType.GetMethods();
MethodInfo[] methods = objType.GetMethods();
foreach (var methodInfo in methods)
int res = TryIndexMethods(luaState, methods, obj, index);
if (res != 0)
return res;
// Fallback to GetRuntimeMethods
methods = objType.GetRuntimeMethods().ToArray();
res = TryIndexMethods(luaState, methods, obj, index);
if (res != 0)
return res;
res = TryGetValueForKeyMethods(luaState, methods, obj, index);
if (res != 0)
return res;
// Try find explicity interface implementation
MethodInfo explicitInterfaceMethod = objType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).
FirstOrDefault(m => m.Name == methodName && m.IsPrivate && m.IsVirtual && m.IsFinal);
if (explicitInterfaceMethod != null)
{
if (methodInfo.Name != "get_Item")
var proxyType = new ProxyType(objType);
var methodWrapper = new LuaMethodWrapper(_translator, obj, proxyType, explicitInterfaceMethod);
var invokeDelegate = new LuaNativeFunction(methodWrapper.InvokeFunction);
SetMemberCache(proxyType, methodName, invokeDelegate);
_translator.PushFunction(luaState, invokeDelegate);
_translator.Push(luaState, true);
return 2;
}
return 0;
}
private int TryGetValueForKeyMethods(LuaState luaState, MethodInfo[] methods, object obj, object index)
{
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.Name != "TryGetValueForKey")
continue;
// Check if the signature matches the input
if (methodInfo.GetParameters().Length != 1)
if (methodInfo.GetParameters().Length != 2)
continue;
ParameterInfo[] actualParams = methodInfo.GetParameters();
if (actualParams.Length != 1)
{
_translator.ThrowError(luaState, "method not found (or no indexer): " + index);
luaState.PushNil();
}
else
{
// Get the index in a form acceptable to the getter
index = _translator.GetAsType(luaState, 2, actualParams[0].ParameterType);
// Get the index in a form acceptable to the getter
index = _translator.GetAsType(luaState, 2, actualParams[0].ParameterType);
// If the index type and the parameter doesn't match, just skip it
if (index == null)
break;
// If the index type and the parameter doesn't match, just skip it
if (index == null)
break;
object[] args = new object[1];
object[] args = new object[2];
// Just call the indexer - if out of bounds an exception will happen
args[0] = index;
// Just call the indexer - if out of bounds an exception will happen
args[0] = index;
try
try
{
bool found = (bool)methodInfo.Invoke(obj, args);
if (!found)
{
object result = methodInfo.Invoke(obj, args);
_translator.Push(luaState, result);
_translator.ThrowError(luaState, "key not found: " + index);
luaState.PushNil();
return 1;
}
catch (TargetInvocationException e)
{
// Provide a more readable description for the common case of key not found
if (e.InnerException is KeyNotFoundException)
_translator.ThrowError(luaState, "key '" + index + "' not found ");
else
_translator.ThrowError(luaState, "exception indexing '" + index + "' " + e.Message);
luaState.PushNil();
}
_translator.Push(luaState, args[1]);
return 1;
}
catch (TargetInvocationException e)
{
// Provide a more readable description for the common case of key not found
if (e.InnerException is KeyNotFoundException)
_translator.ThrowError(luaState, "key '" + index + "' not found ");
else
_translator.ThrowError(luaState, "exception indexing '" + index + "' " + e.Message);
luaState.PushNil();
return 1;
}
}
return 0;
}
// Try find explicity interface implementation
MethodInfo explicitInterfaceMethod = objType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).
FirstOrDefault(m => m.Name == methodName && m.IsPrivate && m.IsVirtual && m.IsFinal);
if (explicitInterfaceMethod != null)
private int TryIndexMethods(LuaState luaState, MethodInfo [] methods, object obj, object index)
{
foreach (MethodInfo methodInfo in methods)
{
var proxyType = new ProxyType(objType);
var methodWrapper = new LuaMethodWrapper(_translator, obj, proxyType, explicitInterfaceMethod);
var invokeDelegate = new LuaNativeFunction(methodWrapper.InvokeFunction);
if (methodInfo.Name != "get_Item")
continue;
SetMemberCache(proxyType, methodName, invokeDelegate);
// Check if the signature matches the input
if (methodInfo.GetParameters().Length != 1)
continue;
_translator.PushFunction(luaState, invokeDelegate);
_translator.Push(luaState, true);
return 2;
}
ParameterInfo[] actualParams = methodInfo.GetParameters();
// Get the index in a form acceptable to the getter
index = _translator.GetAsType(luaState, 2, actualParams[0].ParameterType);
// If the index type and the parameter doesn't match, just skip it
if (index == null)
break;
object[] args = new object[1];
// Just call the indexer - if out of bounds an exception will happen
args[0] = index;
try
{
object result = methodInfo.Invoke(obj, args);
_translator.Push(luaState, result);
return 1;
}
catch (TargetInvocationException e)
{
// Provide a more readable description for the common case of key not found
if (e.InnerException is KeyNotFoundException)
_translator.ThrowError(luaState, "key '" + index + "' not found ");
else
_translator.ThrowError(luaState, "exception indexing '" + index + "' " + e.Message);
luaState.PushNil();
return 1;
}
}
return 0;
}
......@@ -913,11 +980,6 @@ namespace NLua
_translator.ThrowError(luaState, detailMessage); // Pass the original message from trySetMember because it is probably best
}
}
catch (SEHException)
{
// If we are seeing a C++ exception - this must actually be for Lua's private use. Let it handle it
throw;
}
catch (Exception e)
{
ThrowError(luaState, e);
......
......@@ -2573,30 +2573,30 @@ namespace NLuaTest
IDictionary<string,object> obj2 = new Dictionary<string, object>()
{
{ "key1" ,"value1" },
{ "key2" ,"value2" }
{ "key1" ,"value3" },
{ "key2" ,"value4" }
};
lua["obj2"] = obj;
lua["obj2"] = obj2;
lua.DoString("l = obj2.key1");
lua.DoString("m = obj2['key2']");
Assert.AreEqual("value1", lua["l"], "#3");
Assert.AreEqual("value2", lua["m"], "#4");
Assert.AreEqual("value3", lua["l"], "#3");
Assert.AreEqual("value4", lua["m"], "#4");
IDictionary<string, object> obj3 = new System.Dynamic.ExpandoObject();
obj3["key1"] = "value1";
obj3["key2"] = "value2";
obj3["key1"] = "value5";
obj3["key2"] = "value6";
lua["obj3"] = obj;
lua["obj3"] = obj3;
lua.DoString("n = obj3.key1");
lua.DoString("o = obj3['key2']");
Assert.AreEqual("value1", lua["n"], "#5");
Assert.AreEqual("value2", lua["o"], "#6");
Assert.AreEqual("value5", lua["n"], "#5");
Assert.AreEqual("value6", lua["o"], "#6");
}
}
......
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