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 ...@@ -473,74 +473,141 @@ namespace NLua
return PushExtensionMethod(luaState, objType, obj, methodName, method); return PushExtensionMethod(luaState, objType, obj, methodName, method);
} }
// Try to use get_Item to index into this .net object // 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; continue;
// Check if the signature matches the input // Check if the signature matches the input
if (methodInfo.GetParameters().Length != 1) if (methodInfo.GetParameters().Length != 2)
continue; continue;
ParameterInfo[] actualParams = methodInfo.GetParameters(); ParameterInfo[] actualParams = methodInfo.GetParameters();
if (actualParams.Length != 1) // Get the index in a form acceptable to the getter
{ index = _translator.GetAsType(luaState, 2, actualParams[0].ParameterType);
_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);
// If the index type and the parameter doesn't match, just skip it // If the index type and the parameter doesn't match, just skip it
if (index == null) if (index == null)
break; break;
object[] args = new object[1]; object[] args = new object[2];
// Just call the indexer - if out of bounds an exception will happen // Just call the indexer - if out of bounds an exception will happen
args[0] = index; args[0] = index;
try try
{
bool found = (bool)methodInfo.Invoke(obj, args);
if (!found)
{ {
object result = methodInfo.Invoke(obj, args); _translator.ThrowError(luaState, "key not found: " + index);
_translator.Push(luaState, result); luaState.PushNil();
return 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(); _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); if (methodInfo.Name != "get_Item")
var methodWrapper = new LuaMethodWrapper(_translator, obj, proxyType, explicitInterfaceMethod); continue;
var invokeDelegate = new LuaNativeFunction(methodWrapper.InvokeFunction);
SetMemberCache(proxyType, methodName, invokeDelegate); // Check if the signature matches the input
if (methodInfo.GetParameters().Length != 1)
continue;
_translator.PushFunction(luaState, invokeDelegate); ParameterInfo[] actualParams = methodInfo.GetParameters();
_translator.Push(luaState, true);
return 2; // 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; return 0;
} }
...@@ -913,11 +980,6 @@ namespace NLua ...@@ -913,11 +980,6 @@ namespace NLua
_translator.ThrowError(luaState, detailMessage); // Pass the original message from trySetMember because it is probably best _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) catch (Exception e)
{ {
ThrowError(luaState, e); ThrowError(luaState, e);
......
...@@ -2573,30 +2573,30 @@ namespace NLuaTest ...@@ -2573,30 +2573,30 @@ namespace NLuaTest
IDictionary<string,object> obj2 = new Dictionary<string, object>() IDictionary<string,object> obj2 = new Dictionary<string, object>()
{ {
{ "key1" ,"value1" }, { "key1" ,"value3" },
{ "key2" ,"value2" } { "key2" ,"value4" }
}; };
lua["obj2"] = obj; lua["obj2"] = obj2;
lua.DoString("l = obj2.key1"); lua.DoString("l = obj2.key1");
lua.DoString("m = obj2['key2']"); lua.DoString("m = obj2['key2']");
Assert.AreEqual("value1", lua["l"], "#3"); Assert.AreEqual("value3", lua["l"], "#3");
Assert.AreEqual("value2", lua["m"], "#4"); Assert.AreEqual("value4", lua["m"], "#4");
IDictionary<string, object> obj3 = new System.Dynamic.ExpandoObject(); IDictionary<string, object> obj3 = new System.Dynamic.ExpandoObject();
obj3["key1"] = "value1"; obj3["key1"] = "value5";
obj3["key2"] = "value2"; obj3["key2"] = "value6";
lua["obj3"] = obj; lua["obj3"] = obj3;
lua.DoString("n = obj3.key1"); lua.DoString("n = obj3.key1");
lua.DoString("o = obj3['key2']"); lua.DoString("o = obj3['key2']");
Assert.AreEqual("value1", lua["n"], "#5"); Assert.AreEqual("value5", lua["n"], "#5");
Assert.AreEqual("value2", lua["o"], "#6"); 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