Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
NLua
Commits
83fb7adc
Commit
83fb7adc
authored
Sep 13, 2019
by
Vinicius Jarina
Browse files
Fixed `GetMethodFallback` to check `GetRuntimeMethods` and `TryGetValueForKey`.
parent
c3b15c9b
Changes
2
Show whitespace changes
Inline
Side-by-side
src/Metatables.cs
View file @
83fb7adc
...
...
@@ -473,26 +473,56 @@ 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
);
...
...
@@ -500,15 +530,23 @@ namespace NLua
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
;
try
{
object
result
=
methodInfo
.
Invoke
(
obj
,
args
);
_translator
.
Push
(
luaState
,
result
);
bool
found
=
(
bool
)
methodInfo
.
Invoke
(
obj
,
args
);
if
(!
found
)
{
_translator
.
ThrowError
(
luaState
,
"key not found: "
+
index
);
luaState
.
PushNil
();
return
1
;
}
_translator
.
Push
(
luaState
,
args
[
1
]);
return
1
;
}
catch
(
TargetInvocationException
e
)
...
...
@@ -520,27 +558,56 @@ namespace NLua
_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
)
{
var
proxyType
=
new
ProxyType
(
objType
);
var
methodWrapper
=
new
LuaMethodWrapper
(
_translator
,
obj
,
proxyType
,
explicitInterfaceMethod
);
var
invokeDelegate
=
new
LuaNativeFunction
(
methodWrapper
.
InvokeFunction
);
foreach
(
MethodInfo
methodInfo
in
methods
)
{
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
);
...
...
tests/src/LuaTests.cs
View file @
83fb7adc
...
...
@@ -2573,30 +2573,30 @@ namespace NLuaTest
IDictionary
<
string
,
object
>
obj2
=
new
Dictionary
<
string
,
object
>()
{
{
"key1"
,
"value
1
"
},
{
"key2"
,
"value
2
"
}
{
"key1"
,
"value
3
"
},
{
"key2"
,
"value
4
"
}
};
lua
[
"obj2"
]
=
obj
;
lua
[
"obj2"
]
=
obj
2
;
lua
.
DoString
(
"l = obj2.key1"
);
lua
.
DoString
(
"m = obj2['key2']"
);
Assert
.
AreEqual
(
"value
1
"
,
lua
[
"l"
],
"#3"
);
Assert
.
AreEqual
(
"value
2
"
,
lua
[
"m"
],
"#4"
);
Assert
.
AreEqual
(
"value
3
"
,
lua
[
"l"
],
"#3"
);
Assert
.
AreEqual
(
"value
4
"
,
lua
[
"m"
],
"#4"
);
IDictionary
<
string
,
object
>
obj3
=
new
System
.
Dynamic
.
ExpandoObject
();
obj3
[
"key1"
]
=
"value
1
"
;
obj3
[
"key2"
]
=
"value
2
"
;
obj3
[
"key1"
]
=
"value
5
"
;
obj3
[
"key2"
]
=
"value
6
"
;
lua
[
"obj3"
]
=
obj
;
lua
[
"obj3"
]
=
obj
3
;
lua
.
DoString
(
"n = obj3.key1"
);
lua
.
DoString
(
"o = obj3['key2']"
);
Assert
.
AreEqual
(
"value
1
"
,
lua
[
"n"
],
"#5"
);
Assert
.
AreEqual
(
"value
2
"
,
lua
[
"o"
],
"#6"
);
Assert
.
AreEqual
(
"value
5
"
,
lua
[
"n"
],
"#5"
);
Assert
.
AreEqual
(
"value
6
"
,
lua
[
"o"
],
"#6"
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment