Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit10158f4

Browse files
committed
Wrap returned objects in interface if method return type is interface
This allows callers to call all methods of an interface, regardless ofwhether the method was implemented implicitly or explicitly. Before thischange, you had to make an explicit cast to the interface to be able tocall the explicitly implemented method. Consider the following code:```C#namespace Python.Test { public interface ITestInterface { void Foo(); void Bar(); } public class TestImpl : ITestInterface { public void Foo() { }; public void ITestInterface.Bar() { }; public void Baz() { }; public static ITestInterface GetInterface() { return new TestImpl(); } }}```And the following Python code, demonstrating the behavior before thischange:```pythonfrom Python.Test import TestImpl, ITestInterfacetest = TestImpl.GetInterface()test.Foo() # workstest.Bar() # AttributeError: 'TestImpl' object has no attribute 'Bar'test.Baz() # works! - baz```After this change, the behavior is as follows:```test = TestImpl.GetInterface()test.Foo() # workstest.Bar() # workstest.Baz() # AttributeError: 'ITestInterface' object has no attribute 'Baz'```This is a breaking change due to that `Baz` is no longer visible inPython.
1 parent451fae6 commit10158f4

File tree

7 files changed

+92
-14
lines changed

7 files changed

+92
-14
lines changed

‎src/runtime/methodbinder.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i
735735
varn=0;
736736

737737
IntPtrt=Runtime.PyTuple_New(binding.outs+1);
738-
IntPtrv=Converter.ToPython(result,mi.ReturnType);
738+
IntPtrv=MakeReturnValue(result,mi.ReturnType);
739739
Runtime.PyTuple_SetItem(t,n,v);
740740
n++;
741741

@@ -744,7 +744,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i
744744
Typept=pi[i].ParameterType;
745745
if(pi[i].IsOut||pt.IsByRef)
746746
{
747-
v=Converter.ToPython(binding.args[i],pt);
747+
v=MakeReturnValue(binding.args[i],pt.GetElementType());
748748
Runtime.PyTuple_SetItem(t,n,v);
749749
n++;
750750
}
@@ -761,7 +761,24 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i
761761
returnt;
762762
}
763763

764-
returnConverter.ToPython(result,mi.ReturnType);
764+
returnMakeReturnValue(result,mi.ReturnType);
765+
}
766+
767+
/// <summary>
768+
/// Takes care of wrapping an object in an interface object
769+
/// in case the method returns a value of a interface type.
770+
/// </summary>
771+
privateIntPtrMakeReturnValue(objectretVal,TyperetType)
772+
{
773+
if(retVal!=null&&retType.IsInterface)
774+
{
775+
varifaceObj=(InterfaceObject)ClassManager.GetClass(retType);
776+
returnCLRObject.GetInstHandle(retVal,ifaceObj.pyHandle);
777+
}
778+
else
779+
{
780+
returnConverter.ToPython(retVal,retType);
781+
}
765782
}
766783
}
767784

‎src/testing/interfacetest.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ internal interface IInternalInterface
1111
{
1212
}
1313

14-
1514
publicinterfaceISayHello1
1615
{
1716
stringSayHello();
@@ -43,6 +42,22 @@ string ISayHello2.SayHello()
4342
return"hello 2";
4443
}
4544

45+
publicISayHello1GetISayHello1()
46+
{
47+
returnthis;
48+
}
49+
50+
publicvoidGetISayHello2(outISayHello2hello2)
51+
{
52+
hello2=this;
53+
}
54+
55+
publicISayHello1GetNoSayHello(outISayHello2hello2)
56+
{
57+
hello2=null;
58+
returnnull;
59+
}
60+
4661
publicinterfaceIPublic
4762
{
4863
}

‎src/testing/subclasstest.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,24 @@ public static string test_bar(IInterfaceTest x, string s, int i)
8989
}
9090

9191
// test instances can be constructed in managed code
92-
publicstaticIInterfaceTestcreate_instance(Typet)
92+
publicstaticSubClassTestcreate_instance(Typet)
93+
{
94+
return(SubClassTest)t.GetConstructor(newType[]{}).Invoke(newobject[]{});
95+
}
96+
97+
publicstaticIInterfaceTestcreate_instance_interface(Typet)
9398
{
9499
return(IInterfaceTest)t.GetConstructor(newType[]{}).Invoke(newobject[]{});
95100
}
96101

97-
// test instances pass through managed code unchanged
98-
publicstaticIInterfaceTestpass_through(IInterfaceTests)
102+
// test instances pass through managed code unchanged ...
103+
publicstaticSubClassTestpass_through(SubClassTests)
104+
{
105+
returns;
106+
}
107+
108+
// ... but the return type is an interface type, objects get wrapped
109+
publicstaticIInterfaceTestpass_through_interface(IInterfaceTests)
99110
{
100111
returns;
101112
}

‎src/tests/test_generic.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,6 @@ def test_generic_method_type_handling():
319319
assert_generic_method_by_type(ShortEnum,ShortEnum.Zero)
320320
assert_generic_method_by_type(System.Object,InterfaceTest())
321321
assert_generic_method_by_type(InterfaceTest,InterfaceTest(),1)
322-
assert_generic_method_by_type(ISayHello1,InterfaceTest(),1)
323322

324323

325324
deftest_correct_overload_selection():

‎src/tests/test_interface.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,35 @@ def test_explicit_cast_to_interface():
6767
asserti2.SayHello()=='hello 2'
6868
asserthasattr(i2,'SayHello')
6969
assertnothasattr(i2,'HelloProperty')
70+
71+
72+
deftest_interface_object_returned_through_method():
73+
"""Test interface type is used if method return type is interface"""
74+
fromPython.TestimportInterfaceTest
75+
76+
ob=InterfaceTest()
77+
hello1=ob.GetISayHello1()
78+
asserttype(hello1).__name__=='ISayHello1'
79+
80+
asserthello1.SayHello()=='hello 1'
81+
82+
83+
deftest_interface_object_returned_through_out_param():
84+
"""Test interface type is used for out parameters of interface types"""
85+
fromPython.TestimportInterfaceTest
86+
87+
ob=InterfaceTest()
88+
hello2=ob.GetISayHello2(None)
89+
asserttype(hello2).__name__=='ISayHello2'
90+
91+
asserthello2.SayHello()=='hello 2'
92+
93+
94+
deftest_null_interface_object_returned():
95+
"""Test None is used also for methods with interface return types"""
96+
fromPython.TestimportInterfaceTest
97+
98+
ob=InterfaceTest()
99+
hello1,hello2=ob.GetNoSayHello(None)
100+
asserthello1isNone
101+
asserthello2isNone

‎src/tests/test_method.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,10 @@ def test_explicit_overload_selection():
564564
value=MethodTest.Overloaded.__overloads__[InterfaceTest](inst)
565565
assertvalue.__class__==inst.__class__
566566

567+
iface_class=ISayHello1(InterfaceTest()).__class__
567568
value=MethodTest.Overloaded.__overloads__[ISayHello1](inst)
568-
assertvalue.__class__==inst.__class__
569+
assertvalue.__class__!=inst.__class__
570+
assertvalue.__class__==iface_class
569571

570572
atype=Array[System.Object]
571573
value=MethodTest.Overloaded.__overloads__[str,int,atype](

‎src/tests/test_subclass.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,10 @@ def test_interface():
104104
assertob.bar("bar",2)=="bar/bar"
105105
assertFunctionsTest.test_bar(ob,"bar",2)=="bar/bar"
106106

107-
x=FunctionsTest.pass_through(ob)
108-
assertid(x)==id(ob)
107+
# pass_through will convert from InterfaceTestClass -> IInterfaceTest,
108+
# causing a new wrapper object to be created. Hence id will differ.
109+
x=FunctionsTest.pass_through_interface(ob)
110+
assertid(x)!=id(ob)
109111

110112

111113
deftest_derived_class():
@@ -173,14 +175,14 @@ def test_create_instance():
173175
assertid(x)==id(ob)
174176

175177
InterfaceTestClass=interface_test_class_fixture(test_create_instance.__name__)
176-
ob2=FunctionsTest.create_instance(InterfaceTestClass)
178+
ob2=FunctionsTest.create_instance_interface(InterfaceTestClass)
177179
assertob2.foo()=="InterfaceTestClass"
178180
assertFunctionsTest.test_foo(ob2)=="InterfaceTestClass"
179181
assertob2.bar("bar",2)=="bar/bar"
180182
assertFunctionsTest.test_bar(ob2,"bar",2)=="bar/bar"
181183

182-
y=FunctionsTest.pass_through(ob2)
183-
assertid(y)==id(ob2)
184+
y=FunctionsTest.pass_through_interface(ob2)
185+
assertid(y)!=id(ob2)
184186

185187

186188
deftest_events():

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp