[Python.NET] Re: Wrap in interface (#1240)

Victor “LOST” Milovanov <[email protected]> Mon, 8 Feb 2021 11:22:21 -0800
Newsgroups gmane.comp.python.dotnet
Message-ID <[email protected]>
--===============5194068437164212787==
Content-Type: multipart/related;
	boundary="_F09021FA-159C-4F90-AFE5-8EC668AFAB58_"

--_F09021FA-159C-4F90-AFE5-8EC668AFAB58_
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="utf-8"

<html xmlns:v=3D"urn:schemas-microsoft-com:vml" xmlns:o=3D"urn:schemas-micr=
osoft-com:office:office" xmlns:w=3D"urn:schemas-microsoft-com:office:word" =
xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" xmlns=3D"http:=
//www.w3.org/TR/REC-html40"><head><meta http-equiv=3DContent-Type content=
=3D"text/html; charset=3Dutf-8"><meta name=3DGenerator content=3D"Microsoft=
 Word 15 (filtered medium)"><!--[if !mso]><style>v\:* {behavior:url(#defaul=
t#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style><![endif]--><style><!--
/* Font Definitions */
@font-face
	{font-family:"Cambria Math";
	panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
	{font-family:Calibri;
	panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin:0in;
	font-size:11.0pt;
	font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
	{mso-style-priority:99;
	color:blue;
	text-decoration:underline;}
p.xmsonormal, li.xmsonormal, div.xmsonormal
	{mso-style-name:x_msonormal;
	margin:0in;
	font-size:11.0pt;
	font-family:"Calibri",sans-serif;}
p.xmsolistparagraph, li.xmsolistparagraph, div.xmsolistparagraph
	{mso-style-name:x_msolistparagraph;
	margin-top:0in;
	margin-right:0in;
	margin-bottom:0in;
	margin-left:.5in;
	font-size:11.0pt;
	font-family:"Calibri",sans-serif;}
p.xxmsonormal, li.xxmsonormal, div.xxmsonormal
	{mso-style-name:x_xmsonormal;
	margin:0in;
	font-size:11.0pt;
	font-family:"Calibri",sans-serif;}
.MsoChpDefault
	{mso-style-type:export-only;}
@page WordSection1
	{size:8.5in 11.0in;
	margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
	{page:WordSection1;}
/* List Definitions */
@list l0
	{mso-list-id:670642116;
	mso-list-template-ids:-1;}
ol
	{margin-bottom:0in;}
ul
	{margin-bottom:0in;}
--></style></head><body lang=3DEN-US link=3Dblue vlink=3D"#954F72" style=3D=
'word-wrap:break-word'><div class=3DWordSection1><p class=3DMsoNormal>Prior=
 to the change the only way to call explicitly implemented member of an int=
erface was to call it through the interface type, e.g. System.IDisposable.D=
ispose(instance).</p><p class=3DMsoNormal><o:p>&nbsp;</o:p></p><div style=
=3D'mso-element:para-border-div;border:none;border-top:solid #E1E1E1 1.0pt;=
padding:3.0pt 0in 0in 0in'><p class=3DMsoNormal style=3D'border:none;paddin=
g:0in'><b>From: </b><a href=3D"mailto:[email protected]">Mohamed Kou=
baa</a><br><b>Sent: </b>Monday, February 8, 2021 11:19 AM<br><b>To: </b><a =
href=3D"mailto:[email protected]">A list for users and developers of Pyt=
hon.NET</a><br><b>Subject: </b>[Python.NET] Re: Wrap in interface (#1240)</=
p></div><p class=3DMsoNormal><o:p>&nbsp;</o:p></p><div><p class=3DMsoNormal=
><span style=3D'font-size:12.0pt;color:black'>Victor,<o:p></o:p></span></p>=
</div><div><p class=3DMsoNormal><span style=3D'font-size:12.0pt;color:black=
'><o:p>&nbsp;</o:p></span></p></div><div><p class=3DMsoNormal><span style=
=3D'font-size:12.0pt;color:black;background:white'>Our API is C# and some o=
f our users actually directly use C# to access them and don't use python.&n=
bsp; We don't intend to change the API</span><span style=3D'font-size:12.0p=
t;color:black'>.&nbsp; Of course, users may have to change their scripts to=
 be python3 compatible when they opt into using our API from CPython, but w=
e expect most anything unrelated to 2to3 to continue to work.<o:p></o:p></s=
pan></p></div><div><p class=3DMsoNormal><span style=3D'font-size:12.0pt;col=
or:black'><o:p>&nbsp;</o:p></span></p></div><div><p class=3DMsoNormal><span=
 style=3D'font-size:12.0pt;color:black'>My expectation is that if a method/=
property returns an object using the interface but the concrete class which=
 it returns implements a given method, then hasattr should find it.&nbsp; I=
 think options 4&amp;5 do what I need (but isn't option 4 what we had prior=
 to #1240?)<o:p></o:p></span></p></div><div><p class=3DMsoNormal><span styl=
e=3D'font-size:12.0pt;color:black'><o:p>&nbsp;</o:p></span></p></div><div><=
p class=3DMsoNormal><span style=3D'font-size:12.0pt;color:black'>Thanks,<o:=
p></o:p></span></p></div><div><p class=3DMsoNormal><span style=3D'font-size=
:12.0pt;color:black'>Mohamed<o:p></o:p></span></p></div><p class=3DMsoNorma=
l><img border=3D0 width=3D694 height=3D2 style=3D'width:7.2291in;height:.02=
08in' id=3D"Horizontal_x0020_Line_x0020_1" src=3D"cid:image003.png@01D6FE0C=
.AB085140"><o:p></o:p></p><div id=3DdivRplyFwdMsg><p class=3DMsoNormal><b><=
span style=3D'color:black'>From:</span></b><span style=3D'color:black'> Vic=
tor =E2=80=9CLOST=E2=80=9D Milovanov &lt;[email protected]&gt;<br><b>Se=
nt:</b> Monday, February 8, 2021 12:56 PM<br><b>To:</b> A list for users an=
d developers of Python.NET &lt;[email protected]&gt;<br><b>Subject:</b> =
[Python.NET] Re: Wrap in interface (#1240)</span> <o:p></o:p></p><div><p cl=
ass=3DMsoNormal>&nbsp;<o:p></o:p></p></div></div><div><div style=3D'border:=
solid #9C6500 1.0pt;padding:2.0pt 2.0pt 2.0pt 2.0pt'><p style=3D'line-heigh=
t:12.0pt;background:#FFEB9C'><b><span style=3D'font-size:10.0pt;color:red'>=
[External Sender]</span></b></p></div><div><div><p class=3Dxmsonormal>A dum=
p of thoughts on the matter:</p><p class=3Dxmsonormal>&nbsp;</p><ol style=
=3D'margin-top:0in' start=3D1 type=3D1><li class=3Dxmsolistparagraph style=
=3D'margin-left:0in;mso-list:l0 level1 lfo1'>IronPython is Python 2 only, P=
ython.NET 3.0+ is Python 3 only. Why not use 2.5.x until you are comfortabl=
e to change API?<o:p></o:p></li><li class=3Dxmsolistparagraph style=3D'marg=
in-left:0in;mso-list:l0 level1 lfo1'>Flag is possible, but I would not reco=
mmend that approach, because it makes combining multiple libraries that use=
 different global flags problematic.<o:p></o:p></li><li class=3Dxmsolistpar=
agraph style=3D'margin-left:0in;mso-list:l0 level1 lfo1'>Perhaps we could a=
llow codecs to handle instances of wrapped interfaces (actually, isn=E2=80=
=99t that currently allowed?)<o:p></o:p></li><li class=3Dxmsolistparagraph =
style=3D'margin-left:0in;mso-list:l0 level1 lfo1'>IronPython apparently all=
ows explicit interface implementations to be called (instead of returning i=
nterface-wrapped instances), if there=E2=80=99s no conflict with regular me=
thods. Perhaps we should consider this as an option.<o:p></o:p></li><li cla=
ss=3Dxmsolistparagraph style=3D'margin-left:0in;mso-list:l0 level1 lfo1'>Al=
ternatively, we can keep wrapped instances, but allow to resolve public mem=
bers too if the method is not found in the interface. I like this option be=
tter than 4, because actual type of an element in ISomething[] won=E2=80=99=
t change behavior of invoking interface member. It might still affect `hasa=
ttr`, but this is somewhat expected.<o:p></o:p></li></ol><p class=3Dxmsonor=
mal>&nbsp;</p><p class=3Dxmsonormal>Regards,</p><p class=3Dxmsonormal>Victo=
r</p><p class=3Dxmsonormal>&nbsp;</p><div style=3D'border:none;border-top:s=
olid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in'><p class=3Dxmsonormal><b>From=
: </b><a href=3D"mailto:[email protected]">Mohamed Koubaa</a><br><b>=
Sent: </b>Monday, February 8, 2021 8:34 AM<br><b>To: </b><a href=3D"mailto:=
[email protected]">A list for users and developers of Python.NET</a><br>=
<b>Subject: </b>[Python.NET] Re: Wrap in interface (#1240)</p></div><p clas=
s=3Dxmsonormal>&nbsp;</p><div><p class=3Dxmsonormal><span style=3D'font-siz=
e:12.0pt;color:black'>Victor,</span></p></div><div><p class=3Dxmsonormal><s=
pan style=3D'font-size:12.0pt;color:black'>&nbsp;</span></p></div><div><p c=
lass=3Dxmsonormal><span style=3D'font-size:12.0pt;color:black'>Sorry for th=
e late response.&nbsp; I think what I would need is some kind of flag in th=
e python runtime to choose the old behavior (without having to have my own =
branch).&nbsp; Of course there is a workaround but we've invested a lot of =
time in designing the API for both CPython &amp; IronPython and it would be=
 ideal if they did not differ in this way.&nbsp;&nbsp;</span></p></div><div=
><p class=3Dxmsonormal><span style=3D'font-size:12.0pt;color:black'>&nbsp;<=
/span></p></div><div><p class=3Dxmsonormal><span style=3D'font-size:12.0pt;=
color:black'>This could be a global flag on the runtime and/or an attribute=
 on a class/interface to decide on a granular level whether the specific cl=
ass/interface will use interface method binding or instance method binding.=
</span></p></div><div><p class=3Dxmsonormal><span style=3D'font-size:12.0pt=
;color:black'>&nbsp;</span></p></div><div><p class=3Dxmsonormal><span style=
=3D'font-size:12.0pt;color:black'>Thoughts?</span></p></div><div><p class=
=3Dxmsonormal><span style=3D'font-size:12.0pt;color:black'>&nbsp;</span></p=
></div><div><p class=3Dxmsonormal><span style=3D'font-size:12.0pt;color:bla=
ck'>Thanks!</span></p></div><div><p class=3Dxmsonormal><span style=3D'font-=
size:12.0pt;color:black'>Mohamed</span></p></div><p class=3Dxmsonormal><img=
 border=3D0 width=3D694 height=3D2 style=3D'width:7.2291in;height:.0208in' =
id=3D"x_Horizontal_x0020_Line_x0020_1" src=3D"cid:image001.png-CFHuyTl/[email protected]=
B1250"></p><div id=3D"x_divRplyFwdMsg"><p class=3Dxmsonormal><b><span style=
=3D'color:black'>From:</span></b><span style=3D'color:black'> Victor =E2=80=
=9CLOST=E2=80=9D Milovanov &lt;[email protected]&gt;<br><b>Sent:</b> Mo=
nday, November 2, 2020 8:35 PM<br><b>To:</b> A list for users and developer=
s of Python.NET &lt;[email protected]&gt;<br><b>Subject:</b> [Python.NET=
] Re: Wrap in interface (#1240)</span> </p><div><p class=3Dxmsonormal>&nbsp=
;</p></div></div><div><div style=3D'border:solid #9C6500 1.0pt;padding:2.0p=
t 2.0pt 2.0pt 2.0pt'><p style=3D'line-height:12.0pt;background:#FFEB9C'><b>=
<span style=3D'font-size:10.0pt;color:red'>[External Sender]</span></b></p>=
</div><div><div><p class=3Dxxmsonormal>The original bug report described a =
similar problem, except the behavior without defaulting to stricter interfa=
ce types is very unintuitive. Imagine you have a well documented library, t=
hat exposes property <b>Prop</b> of type <b>IInterface</b>. When specific c=
lass implements some <b>Method</b> &nbsp;in <b>IInterface</b> explicitly (w=
hich arguably is a very minor implementation detail), and you call <b>Prop.=
Method()</b> in Python, it can fail with AttributeError despite the documen=
tation claiming this method exists on the interface. This is very confusing=
. IMHO, more confusing, than inability to get Length of an element of <b>IS=
hape[]</b>.</p><p class=3Dxxmsonormal>&nbsp;</p><p class=3Dxxmsonormal>We c=
ould try to improve the situation for Python folks by allowing interface in=
stance wrappers to fall back to the original class instance in case the att=
ribute is not found in the interface itself. I think this might still be pr=
oblematic, as it would make the behavior of hasattr and other similar funct=
ions a bit surprising.</p><p class=3Dxxmsonormal>&nbsp;</p><p class=3Dxxmso=
normal>Regardless, there=E2=80=99s a workaround for the scenario you descri=
bed which is just doing <b>m.GetShape(1).__raw_implementation__.Length </b>=
or </p><p class=3Dxxmsonormal><b>m.GetShape(1).__implementation__.Length </=
b>depending if you need an encoded instance.</p><p class=3Dxxmsonormal>&nbs=
p;</p><p class=3Dxxmsonormal>Regards,</p><p class=3Dxxmsonormal>Victor Milo=
vanov</p><p class=3Dxxmsonormal>&nbsp;</p><div style=3D'border:none;border-=
top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in'><p class=3Dxxmsonormal><=
b>From: </b><a href=3D"mailto:[email protected]">Mohamed Koubaa</a><=
br><b>Sent: </b>Monday, November 2, 2020 6:15 PM<br><b>To: </b><a href=3D"m=
ailto:[email protected]">[email protected]</a><br><b>Subject: </b>[Py=
thon.NET] Wrap in interface (#1240)</p></div><p class=3Dxxmsonormal>&nbsp;<=
/p><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;color:black'=
>Hello,</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-siz=
e:12.0pt;color:black'>&nbsp;</span></p></div><div><p class=3Dxxmsonormal><s=
pan style=3D'font-size:12.0pt;color:black'>This <a href=3D"https://nam10.sa=
felinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgithub.com%2Fpythonnet%=
2Fpythonnet%2Fpull%2F1240&amp;data=3D04%7C01%7Cmohamed.koubaa%40ansys.com%7=
C4b457216f75446301a4508d8cc634c3b%7C34c6ce6715b84eff80e952da8be89706%7C0%7C=
0%7C637484074196952423%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoi=
V2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=3DcAFUSSzeNl11sru%2=
B1ZNS8EjdoqhST%2FAGvY73dUQgV9U%3D&amp;reserved=3D0" title=3D"https://github=
.com/pythonnet/pythonnet/pull/1240">PR</a>&nbsp;changed behavior of pythonn=
et to use stricter typing when a method returns an interface.&nbsp; I'd lik=
e a way to opt-out of this behavior, and I'll share a representative use-ca=
se below.&nbsp; The tl;dr is that python is a dynamic language and I expect=
 the C# objects which pythonnet wraps to behave more like &quot;dynamic&quo=
t; and less like the static types on the interface.</span></p></div><div><p=
 class=3Dxxmsonormal><span style=3D'font-size:12.0pt;color:black'>&nbsp;</s=
pan></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;c=
olor:black'>**** C# code ****</span></p></div><div><p class=3Dxxmsonormal><=
span style=3D'font-size:12.0pt;font-family:"Courier New";color:black'>names=
pace Example1</span><span style=3D'font-size:12.0pt;color:black'> </span></=
p><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"=
Courier New";color:black'>{</span></p></div><div><p class=3Dxxmsonormal><sp=
an style=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&nbsp; =
&nbsp; public enum ShapeType</span></p></div><div><p class=3Dxxmsonormal><s=
pan style=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&nbsp;=
 &nbsp; {</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-s=
ize:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbs=
p; Square,</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-=
size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nb=
sp; Circle</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-=
size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; }</span></=
p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-fa=
mily:"Courier New";color:black'>&nbsp; &nbsp; public interface IShape</span=
></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font=
-family:"Courier New";color:black'>&nbsp; &nbsp; {</span></p></div><div><p =
class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier Ne=
w";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; void Draw();</span></p></div><d=
iv><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;color:black'>&nbs=
p;</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.=
0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; doub=
le Area { get; }</span></p></div><div><p class=3Dxxmsonormal><span style=3D=
'font-size:12.0pt;color:black'>&nbsp;</span></p></div><div><p class=3Dxxmso=
normal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:blac=
k'>&nbsp; &nbsp; &nbsp; &nbsp; ShapeType Type { get; }</span></p></div><div=
><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courie=
r New";color:black'>&nbsp; &nbsp; }</span></p></div><div><p class=3Dxxmsono=
rmal><span style=3D'font-size:12.0pt;color:black'>&nbsp;</span></p></div><d=
iv><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Cour=
ier New";color:black'>&nbsp; &nbsp; public class Square : IShape</span></p>=
</div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-fami=
ly:"Courier New";color:black'>&nbsp; &nbsp; {</span></p></div><div><p class=
=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier New";co=
lor:black'>&nbsp; &nbsp; &nbsp; &nbsp; public double Length { get; }</span>=
</p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-=
family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; public Square=
(double length)</span></p></div><div><p class=3Dxxmsonormal><span style=3D'=
font-size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp=
; &nbsp; {</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-=
size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nb=
sp; &nbsp; &nbsp; Length =3D length;</span></p></div><div><p class=3Dxxmson=
ormal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black=
'>&nbsp; &nbsp; &nbsp; &nbsp; }</span></p></div><div><p class=3Dxxmsonormal=
><span style=3D'font-size:12.0pt;color:black'>&nbsp;</span></p></div><div><=
p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier =
New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; public void Draw() {}</span><=
/p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-f=
amily:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; public double =
Area { get { return Length * Length; } }</span></p></div><div><p class=3Dxx=
msonormal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:b=
lack'>&nbsp; &nbsp; &nbsp; &nbsp; public ShapeType Type { get { return Shap=
eType.Square; } }</span></p></div><div><p class=3Dxxmsonormal><span style=
=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; }=
</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0p=
t;color:black'>&nbsp;</span></p></div><div><p class=3Dxxmsonormal><span sty=
le=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp;=
 public class Circle : IShape</span></p></div><div><p class=3Dxxmsonormal><=
span style=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&nbsp=
; &nbsp; {</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-=
size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nb=
sp; public double Radius { get; }</span></p></div><div><p class=3Dxxmsonorm=
al><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&=
nbsp; &nbsp; &nbsp; &nbsp; public Circle(double radius)</span></p></div><di=
v><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Couri=
er New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; {</span></p></div><div><p =
class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier Ne=
w";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Radius =3D radius=
;</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0=
pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; }</sp=
an></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;co=
lor:black'>&nbsp;</span></p></div><div><p class=3Dxxmsonormal><span style=
=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &=
nbsp; &nbsp; public void Draw() {}</span></p></div><div><p class=3Dxxmsonor=
mal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black'>=
&nbsp; &nbsp; &nbsp; &nbsp; public double Area { get { return Math.PI * Rad=
ius * Radius; } }</span></p></div><div><p class=3Dxxmsonormal><span style=
=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &=
nbsp; &nbsp; public ShapeType Type { get { return ShapeType.Circle; } }</sp=
an></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;fo=
nt-family:"Courier New";color:black'>&nbsp; &nbsp; }</span></p></div><div><=
p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;color:black'>&nbsp;</=
span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;=
font-family:"Courier New";color:black'>&nbsp; &nbsp; public class ShapeData=
Model</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:=
12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; {</span></p></d=
iv><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:=
"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; private Dictionary&l=
t;int, IShape&gt; _shapes =3D new Dictionary&lt;int, IShape&gt;();</span></=
p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-fa=
mily:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; private int _ne=
xtId =3D 1;</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font=
-size:12.0pt;color:black'>&nbsp;</span></p></div><div><p class=3Dxxmsonorma=
l><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&n=
bsp; &nbsp; &nbsp; &nbsp; public int AddShape(IShape shape)</span></p></div=
><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"C=
ourier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; {</span></p></div><div=
><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courie=
r New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int id =3D _n=
extId;</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size=
:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; _shapes[id] =3D shape;</span></p></div><div><p class=3Dxxmson=
ormal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black=
'>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _nextId++;</span></p></div><div=
><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courie=
r New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return id;</s=
pan></p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;f=
ont-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; }</span><=
/p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;color:=
black'>&nbsp;</span></p></div><div><p class=3Dxxmsonormal><span style=3D'fo=
nt-size:12.0pt;font-family:"Courier New";color:black'>&nbsp; &nbsp; &nbsp; =
&nbsp; public IShape GetShape(int id)</span></p></div><div><p class=3Dxxmso=
normal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:blac=
k'>&nbsp; &nbsp; &nbsp; &nbsp; {</span></p></div><div><p class=3Dxxmsonorma=
l><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black'>&n=
bsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return _shapes[id];</span></p></div=
><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"C=
ourier New";color:black'>&nbsp; &nbsp; &nbsp; &nbsp; }</span></p></div><div=
><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courie=
r New";color:black'>&nbsp; &nbsp; }</span></p></div><div><p class=3Dxxmsono=
rmal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black'=
>}</span></p></div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;c=
olor:black'>&nbsp;</span></p></div><div><p class=3Dxxmsonormal><span style=
=3D'font-size:12.0pt;color:black'>&nbsp;</span></p></div><div><p class=3Dxx=
msonormal><span style=3D'font-size:12.0pt;color:black;background:#181A1B'>*=
*** Python code ****</span></p></div><div><p class=3Dxxmsonormal><span styl=
e=3D'font-size:12.0pt;font-family:"Courier New";color:black;background:#131=
516'>&gt;&gt;&gt; import clr</span></p></div><div><p class=3Dxxmsonormal><s=
pan style=3D'font-size:12.0pt;font-family:"Courier New";color:black;backgro=
und:#131516'>&gt;&gt;&gt; clr.AddReference(&quot;Example1&quot;)</span></p>=
</div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-fami=
ly:"Courier New";color:black;background:#131516'>&gt;&gt;&gt; import Exampl=
e1</span></p></div><div><div><p class=3Dxxmsonormal><span style=3D'font-siz=
e:12.0pt;font-family:"Courier New";color:black;background:#131516'>&gt;&gt;=
&gt; sq1 =3D Example1.Square(2.)</span></p></div><div><p class=3Dxxmsonorma=
l><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black;bac=
kground:#131516'>&gt;&gt;&gt; ci1 =3D Example1.Circle(1.3)</span></p></div>=
<div><p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Co=
urier New";color:black;background:#131516'>&gt;&gt;&gt; sq2 =3D Example1.Sq=
uare(2.5)</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-s=
ize:12.0pt;font-family:"Courier New";color:black;background:#131516'>&gt;&g=
t;&gt; m =3D Example1.ShapeDataModel()</span></p></div><div><p class=3Dxxms=
onormal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:bla=
ck;background:#131516'>&gt;&gt;&gt; m.AddShape(sq1)</span></p></div><div><p=
 class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier N=
ew";color:black;background:#131516'>1</span></p></div><div><p class=3Dxxmso=
normal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:blac=
k;background:#131516'>&gt;&gt;&gt; m.AddShape(sq2)</span></p></div><div><p =
class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier Ne=
w";color:black;background:#131516'>2</span></p></div><div><p class=3Dxxmson=
ormal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black=
;background:#131516'>&gt;&gt;&gt; m.AddShape(ci1)</span></p></div><div><p c=
lass=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier New=
";color:black;background:#131516'>3</span></p></div><div><p class=3Dxxmsono=
rmal><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black;=
background:#131516'>&gt;&gt;&gt; m.GetShape(2)</span></p></div><div><p clas=
s=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier New";c=
olor:black;background:#131516'>&lt;Example1.IShape object at 0x000002A3448A=
09A0&gt;</span></p></div><div><p class=3Dxxmsonormal><span style=3D'font-si=
ze:12.0pt;font-family:"Courier New";color:black;background:#131516'>&gt;&gt=
;&gt; m.GetShape(2).Area</span></p></div><div><p class=3Dxxmsonormal><span =
style=3D'font-size:12.0pt;font-family:"Courier New";color:black;background:=
#131516'>6.25</span></p></div><div><p class=3Dxxmsonormal><span style=3D'fo=
nt-size:12.0pt;font-family:"Courier New";color:black;background:#131516'>&g=
t;&gt;&gt; m.GetShape(2).Length</span></p></div><div><p class=3Dxxmsonormal=
><span style=3D'font-size:12.0pt;font-family:"Courier New";color:black;back=
ground:#131516'>Traceback (most recent call last):</span></p></div><div><p =
class=3Dxxmsonormal><span style=3D'font-size:12.0pt;font-family:"Courier Ne=
w";color:#ED5C57;background:#131516'>&nbsp; File &quot;&lt;stdin&gt;&quot;,=
 line 1, in &lt;module&gt;</span></p></div><div><p class=3Dxxmsonormal><spa=
n style=3D'font-size:12.0pt;font-family:"Courier New";color:#ED5C57;backgro=
und:#131516'>AttributeError: 'IShape' object has no attribute 'Length'</spa=
n></p></div></div><div><p class=3Dxxmsonormal style=3D'margin-bottom:12.0pt=
'>&nbsp;</p></div><div><p class=3Dxxmsonormal><span style=3D'font-size:12.0=
pt;color:black;background:#131516'>**** summary ****</span></p></div><div><=
p class=3Dxxmsonormal><span style=3D'font-size:12.0pt;color:black;backgroun=
d:#131516'>This factory and/or datamodel pattern is very common in my codeb=
ase and probably also lots of object oriented systems.&nbsp; The mentioned =
PR breaks this common design pattern in C# objects wrapped by pythonnet, an=
d I would like a way to opt-out of it.&nbsp; Maybe an attribute on the meth=
od which returns an interface can be used, or maybe something global to swi=
tch this behavior.&nbsp; I think perhaps the original bug might also have b=
een fixed in a different way.&nbsp;</span></p></div><div><p class=3Dxxmsono=
rmal style=3D'margin-bottom:12.0pt'>&nbsp;</p></div><p class=3Dxxmsonormal>=
<span style=3D'font-size:12.0pt;color:black;background:#131516'>Thanks!<br>=
Mohamed</span></p></div></div></div><p class=3Dxxmsonormal>&nbsp;</p></div>=
</div></div><p class=3Dxmsonormal>&nbsp;</p><p class=3DMsoNormal><o:p>&nbsp=
;</o:p></p></div></body></html>=

--_F09021FA-159C-4F90-AFE5-8EC668AFAB58_
Content-Type: image/png; name="43D2152F8F3A439D958284C885825CCD.png"
Content-ID: <image003.png-wd3/[email protected]>
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="43D2152F8F3A439D958284C885825CCD.png"

iVBORw0KGgoAAAANSUhEUgAAArYAAAACCAYAAACtx5+mAAAAAXNSR0IArs4c6QAAAARnQU1BAACx
jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAlSURBVFhH7cMBDQAABAAw/UtJIIEw5GD/9gAA
gBeyelRV9faeBRsQNwwY9nKzAAAAAElFTkSuQmCC

--_F09021FA-159C-4F90-AFE5-8EC668AFAB58_
Content-Type: IMAGE/PNG; name="C081996CDAA945DBACD618306EE5771E.png"
Content-ID: <image001.png-CFHuyTl/[email protected]>
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="C081996CDAA945DBACD618306EE5771E.png"

iVBORw0KGgoAAAANSUhEUgAAArYAAAACCAYAAACtx5+mAAAAAXNSR0IArs4c6QAAAARnQU1BAACx
jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAlSURBVFhH7cMBDQAABAAw/UtJIIEw5GD/9gAA
gBeyelRV9faeBRsQNwwY9nKzAAAAAElFTkSuQmCC

--_F09021FA-159C-4F90-AFE5-8EC668AFAB58_--

--===============5194068437164212787==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
PythonNet mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/pythonnet.python.org/
Member address: [email protected]

--===============5194068437164212787==--