Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cfe1585

Browse files
authored
Merge pull request #1998 from filmor/fix-derived-generic-interface
Fix implementing a generic interface with a Python class
2 parents cc364c3 + 5c1e02f commit cfe1585

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

src/runtime/Types/ClassDerived.cs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuild
436436
il.Emit(OpCodes.Ldloc_0);
437437

438438
il.Emit(OpCodes.Ldtoken, method);
439+
il.Emit(OpCodes.Ldtoken, method.DeclaringType);
439440
#pragma warning disable CS0618 // PythonDerivedType is for internal use only
440441
if (method.ReturnType == typeof(void))
441442
{
@@ -505,6 +506,7 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde
505506

506507
il.DeclareLocal(typeof(object[]));
507508
il.DeclareLocal(typeof(RuntimeMethodHandle));
509+
il.DeclareLocal(typeof(RuntimeTypeHandle));
508510

509511
// this
510512
il.Emit(OpCodes.Ldarg_0);
@@ -546,6 +548,11 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde
546548
il.Emit(OpCodes.Ldloca_S, 1);
547549
il.Emit(OpCodes.Initobj, typeof(RuntimeMethodHandle));
548550
il.Emit(OpCodes.Ldloc_1);
551+
552+
// type handle is also not required
553+
il.Emit(OpCodes.Ldloca_S, 2);
554+
il.Emit(OpCodes.Initobj, typeof(RuntimeTypeHandle));
555+
il.Emit(OpCodes.Ldloc_2);
549556
#pragma warning disable CS0618 // PythonDerivedType is for internal use only
550557

551558
// invoke the method
@@ -698,7 +705,7 @@ public class PythonDerivedType
698705
/// class) it calls it, otherwise it calls the base method.
699706
/// </summary>
700707
public static T? InvokeMethod<T>(IPythonDerivedType obj, string methodName, string origMethodName,
701-
object[] args, RuntimeMethodHandle methodHandle)
708+
object[] args, RuntimeMethodHandle methodHandle, RuntimeTypeHandle declaringTypeHandle)
702709
{
703710
var self = GetPyObj(obj);
704711

@@ -724,7 +731,10 @@ public class PythonDerivedType
724731
}
725732

726733
PyObject py_result = method.Invoke(pyargs);
727-
PyTuple? result_tuple = MarshalByRefsBack(args, methodHandle, py_result, outsOffset: 1);
734+
var clrMethod = methodHandle != default
735+
? MethodBase.GetMethodFromHandle(methodHandle, declaringTypeHandle)
736+
: null;
737+
PyTuple? result_tuple = MarshalByRefsBack(args, clrMethod, py_result, outsOffset: 1);
728738
return result_tuple is not null
729739
? result_tuple[0].As<T>()
730740
: py_result.As<T>();
@@ -754,7 +764,7 @@ public class PythonDerivedType
754764
}
755765

756766
public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, string origMethodName,
757-
object?[] args, RuntimeMethodHandle methodHandle)
767+
object?[] args, RuntimeMethodHandle methodHandle, RuntimeTypeHandle declaringTypeHandle)
758768
{
759769
var self = GetPyObj(obj);
760770
if (null != self.Ref)
@@ -779,7 +789,10 @@ public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, s
779789
}
780790

781791
PyObject py_result = method.Invoke(pyargs);
782-
MarshalByRefsBack(args, methodHandle, py_result, outsOffset: 0);
792+
var clrMethod = methodHandle != default
793+
? MethodBase.GetMethodFromHandle(methodHandle, declaringTypeHandle)
794+
: null;
795+
MarshalByRefsBack(args, clrMethod, py_result, outsOffset: 0);
783796
return;
784797
}
785798
}
@@ -811,12 +824,11 @@ public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, s
811824
/// as a tuple of new values for those arguments, and updates corresponding
812825
/// elements of <paramref name="args"/> array.
813826
/// </summary>
814-
private static PyTuple? MarshalByRefsBack(object?[] args, RuntimeMethodHandle methodHandle, PyObject pyResult, int outsOffset)
827+
private static PyTuple? MarshalByRefsBack(object?[] args, MethodBase? method, PyObject pyResult, int outsOffset)
815828
{
816-
if (methodHandle == default) return null;
829+
if (method is null) return null;
817830

818-
var originalMethod = MethodBase.GetMethodFromHandle(methodHandle);
819-
var parameters = originalMethod.GetParameters();
831+
var parameters = method.GetParameters();
820832
PyTuple? outs = null;
821833
int byrefIndex = 0;
822834
for (int i = 0; i < parameters.Length; ++i)

src/testing/interfacetest.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private interface IPrivate
7979
{
8080
}
8181
}
82-
82+
8383
public interface IOutArg
8484
{
8585
string MyMethod_Out(string name, out int index);
@@ -93,4 +93,25 @@ public static int CallMyMethod_Out(IOutArg myInterface)
9393
return index;
9494
}
9595
}
96+
97+
public interface IGenericInterface<T>
98+
{
99+
public T Get(T x);
100+
}
101+
102+
public class SpecificInterfaceUser
103+
{
104+
public SpecificInterfaceUser(IGenericInterface<int> some, int x)
105+
{
106+
some.Get(x);
107+
}
108+
}
109+
110+
public class GenericInterfaceUser<T>
111+
{
112+
public GenericInterfaceUser(IGenericInterface<T> some, T x)
113+
{
114+
some.Get(x);
115+
}
116+
}
96117
}

tests/test_subclass.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import System
1010
import pytest
1111
from Python.Test import (IInterfaceTest, SubClassTest, EventArgsTest,
12-
FunctionsTest)
12+
FunctionsTest, IGenericInterface)
1313
from System.Collections.Generic import List
1414

1515

@@ -29,6 +29,17 @@ def bar(self, x, i):
2929
return InterfaceTestClass
3030

3131

32+
def interface_generic_class_fixture(subnamespace):
33+
34+
class GenericInterfaceImpl(IGenericInterface[int]):
35+
__namespace__ = "Python.Test." + subnamespace
36+
37+
def Get(self, x):
38+
return x
39+
40+
return GenericInterfaceImpl
41+
42+
3243
def derived_class_fixture(subnamespace):
3344
"""Delay creation of class until test starts."""
3445

@@ -306,3 +317,13 @@ class Derived(BaseClass):
306317

307318
import gc
308319
gc.collect()
320+
321+
def test_generic_interface():
322+
from System import Int32
323+
from Python.Test import GenericInterfaceUser, SpecificInterfaceUser
324+
325+
GenericInterfaceImpl = interface_generic_class_fixture(test_generic_interface.__name__)
326+
327+
obj = GenericInterfaceImpl()
328+
SpecificInterfaceUser(obj, Int32(0))
329+
GenericInterfaceUser[Int32](obj, Int32(0))

0 commit comments

Comments
 (0)