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

Mohamed Koubaa <[email protected]> Mon, 8 Feb 2021 15:31:33 +0000
Newsgroups gmane.comp.python.dotnet
Message-ID <SN6PR01MB4976CCEE1E29E0FC89CE0CC8998F9@SN6PR01MB4976.prod.exchangelabs.com>
--===============4369368159843712820==
Content-Language: en-US
Content-Type: multipart/alternative;
	boundary="_000_SN6PR01MB4976CCEE1E29E0FC89CE0CC8998F9SN6PR01MB4976prod_"

--_000_SN6PR01MB4976CCEE1E29E0FC89CE0CC8998F9SN6PR01MB4976prod_
Content-Type: text/plain; charset="Windows-1252"
Content-Transfer-Encoding: quoted-printable

Victor,

Sorry for the late response.  I think what I would need is some kind of fla=
g in the python runtime to choose the old behavior (without having to have =
my own branch).  Of course there is a workaround but we've invested a lot o=
f time in designing the API for both CPython & IronPython and it would be i=
deal if they did not differ in this way.

This could be a global flag on the runtime and/or an attribute on a class/i=
nterface to decide on a granular level whether the specific class/interface=
 will use interface method binding or instance method binding.

Thoughts?

Thanks!
Mohamed
________________________________
From: Victor =93LOST=94 Milovanov <[email protected]>
Sent: Monday, November 2, 2020 8:35 PM
To: A list for users and developers of Python.NET <[email protected]>
Subject: [Python.NET] Re: Wrap in interface (#1240)


[External Sender]

The original bug report described a similar problem, except the behavior wi=
thout defaulting to stricter interface types is very unintuitive. Imagine y=
ou have a well documented library, that exposes property Prop of type IInte=
rface. When specific class implements some Method  in IInterface explicitly=
 (which arguably is a very minor implementation detail), and you call Prop.=
Method() in Python, it can fail with AttributeError despite the documentati=
on claiming this method exists on the interface. This is very confusing. IM=
HO, more confusing, than inability to get Length of an element of IShape[].



We could try to improve the situation for Python folks by allowing interfac=
e instance wrappers to fall back to the original class instance in case the=
 attribute is not found in the interface itself. I think this might still b=
e problematic, as it would make the behavior of hasattr and other similar f=
unctions a bit surprising.



Regardless, there=92s a workaround for the scenario you described which is =
just doing m.GetShape(1).__raw_implementation__.Length or

m.GetShape(1).__implementation__.Length depending if you need an encoded in=
stance.



Regards,

Victor Milovanov



From: Mohamed Koubaa<mailto:[email protected]>
Sent: Monday, November 2, 2020 6:15 PM
To: [email protected]<mailto:[email protected]>
Subject: [Python.NET] Wrap in interface (#1240)



Hello,



This PR<https://nam10.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2=
Fgithub.com%2Fpythonnet%2Fpythonnet%2Fpull%2F1240&data=3D04%7C01%7Cmohamed.=
koubaa%40ansys.com%7C37b0dd3831f140993f6008d87fa1418f%7C34c6ce6715b84eff80e=
952da8be89706%7C0%7C0%7C637399677854765584%7CUnknown%7CTWFpbGZsb3d8eyJWIjoi=
MC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=3Dt=
TftofPt0a7ds4g1qBjLIBXi7iFOgtygMW3Xa3WHF%2Fo%3D&reserved=3D0> changed behav=
ior of pythonnet to use stricter typing when a method returns an interface.=
  I'd like a way to opt-out of this behavior, and I'll share a representati=
ve use-case below.  The tl;dr is that python is a dynamic language and I ex=
pect the C# objects which pythonnet wraps to behave more like "dynamic" and=
 less like the static types on the interface.



**** C# code ****

namespace Example1

{

    public enum ShapeType

    {

        Square,

        Circle

    }

    public interface IShape

    {

        void Draw();



        double Area { get; }



        ShapeType Type { get; }

    }



    public class Square : IShape

    {

        public double Length { get; }

        public Square(double length)

        {

            Length =3D length;

        }



        public void Draw() {}

        public double Area { get { return Length * Length; } }

        public ShapeType Type { get { return ShapeType.Square; } }

    }



    public class Circle : IShape

    {

        public double Radius { get; }

        public Circle(double radius)

        {

            Radius =3D radius;

        }



        public void Draw() {}

        public double Area { get { return Math.PI * Radius * Radius; } }

        public ShapeType Type { get { return ShapeType.Circle; } }

    }



    public class ShapeDataModel

    {

        private Dictionary<int, IShape> _shapes =3D new Dictionary<int, ISh=
ape>();

        private int _nextId =3D 1;



        public int AddShape(IShape shape)

        {

            int id =3D _nextId;

            _shapes[id] =3D shape;

            _nextId++;

            return id;

        }



        public IShape GetShape(int id)

        {

            return _shapes[id];

        }

    }

}





**** Python code ****

>>> import clr

>>> clr.AddReference("Example1")

>>> import Example1

>>> sq1 =3D Example1.Square(2.)

>>> ci1 =3D Example1.Circle(1.3)

>>> sq2 =3D Example1.Square(2.5)

>>> m =3D Example1.ShapeDataModel()

>>> m.AddShape(sq1)

1

>>> m.AddShape(sq2)

2

>>> m.AddShape(ci1)

3

>>> m.GetShape(2)

<Example1.IShape object at 0x000002A3448A09A0>

>>> m.GetShape(2).Area

6.25

>>> m.GetShape(2).Length

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

AttributeError: 'IShape' object has no attribute 'Length'



**** summary ****

This factory and/or datamodel pattern is very common in my codebase and pro=
bably also lots of object oriented systems.  The mentioned PR breaks this c=
ommon design pattern in C# objects wrapped by pythonnet, and I would like a=
 way to opt-out of it.  Maybe an attribute on the method which returns an i=
nterface can be used, or maybe something global to switch this behavior.  I=
 think perhaps the original bug might also have been fixed in a different w=
ay.



Thanks!
Mohamed



--_000_SN6PR01MB4976CCEE1E29E0FC89CE0CC8998F9SN6PR01MB4976prod_
Content-Type: text/html; charset="Windows-1252"
Content-Transfer-Encoding: quoted-printable

<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3DWindows-1=
252">
<style type=3D"text/css" style=3D"display:none;"> P {margin-top:0;margin-bo=
ttom:0;} </style>
</head>
<body dir=3D"ltr">
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
Victor,</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
Sorry for the late response.&nbsp; I think what I would need is some kind o=
f flag in the python runtime to choose the old behavior (without having to =
have my own branch).&nbsp; Of course there is a workaround but we've invest=
ed 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;</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
This could be a global flag on the runtime and/or an attribute on a class/i=
nterface to decide on a granular level whether the specific class/interface=
 will use interface method binding or instance method binding.</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
Thoughts?</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
Thanks!</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
Mohamed</div>
<div id=3D"appendonsend"></div>
<hr style=3D"display:inline-block;width:98%" tabindex=3D"-1">
<div id=3D"divRplyFwdMsg" dir=3D"ltr"><font face=3D"Calibri, sans-serif" st=
yle=3D"font-size:11pt" color=3D"#000000"><b>From:</b> Victor =93LOST=94 Mil=
ovanov &lt;[email protected]&gt;<br>
<b>Sent:</b> Monday, November 2, 2020 8:35 PM<br>
<b>To:</b> A list for users and developers of Python.NET &lt;pythonnet@pyth=
on.org&gt;<br>
<b>Subject:</b> [Python.NET] Re: Wrap in interface (#1240)</font>
<div>&nbsp;</div>
</div>
<style>
<!--
@font-face
	{font-family:"Cambria Math"}
@font-face
	{font-family:Calibri}
p.x_MsoNormal, li.x_MsoNormal, div.x_MsoNormal
	{margin:0in;
	font-size:11.0pt;
	font-family:"Calibri",sans-serif}
a:link, span.x_MsoHyperlink
	{color:blue;
	text-decoration:underline}
.x_MsoChpDefault
	{}
@page WordSection1
	{margin:1.0in 1.0in 1.0in 1.0in}
div.x_WordSection1
	{}
-->
</style>
<div lang=3D"EN-US" link=3D"blue" vlink=3D"#954F72">
<div style=3D"border:solid #9C6500 1.0pt; padding:2.0pt 2.0pt 2.0pt 2.0pt">
<p style=3D"line-height:12.0pt; background:#FFEB9C"><b><span lang=3D"EN-US"=
 style=3D"font-size:10.0pt; color:red">[External Sender]</span></b></p>
</div>
<div>
<div class=3D"x_WordSection1">
<p class=3D"x_MsoNormal">The original bug report described a similar proble=
m, except the behavior without defaulting to stricter interface types is ve=
ry unintuitive. Imagine you have a well documented library, that exposes pr=
operty
<b>Prop</b> of type <b>IInterface</b>. When specific class implements some =
<b>Method</b> &nbsp;in
<b>IInterface</b> explicitly (which arguably is a very minor implementation=
 detail), and you call
<b>Prop.Method()</b> in Python, it can fail with AttributeError despite the=
 documentation claiming this method exists on the interface. This is very c=
onfusing. IMHO, more confusing, than inability to get Length of an element =
of
<b>IShape[]</b>.<b></b></p>
<p class=3D"x_MsoNormal">&nbsp;</p>
<p class=3D"x_MsoNormal">We could try to improve the situation for Python f=
olks by allowing interface instance wrappers to fall back to the original c=
lass instance in case the attribute is not found in the interface itself. I=
 think this might still be problematic,
 as it would make the behavior of hasattr and other similar functions a bit=
 surprising.</p>
<p class=3D"x_MsoNormal">&nbsp;</p>
<p class=3D"x_MsoNormal">Regardless, there=92s a workaround for the scenari=
o you described which is just doing
<b>m.GetShape(1).__raw_implementation__.Length </b>or </p>
<p class=3D"x_MsoNormal"><b>m.GetShape(1).__implementation__.Length </b>dep=
ending if you need an encoded instance.</p>
<p class=3D"x_MsoNormal">&nbsp;</p>
<p class=3D"x_MsoNormal">Regards,</p>
<p class=3D"x_MsoNormal">Victor Milovanov</p>
<p class=3D"x_MsoNormal">&nbsp;</p>
<div style=3D"border:none; border-top:solid #E1E1E1 1.0pt; padding:3.0pt 0i=
n 0in 0in">
<p class=3D"x_MsoNormal" style=3D"border:none; padding:0in"><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"mailto:[email protected]">[email protected]</a>=
<br>
<b>Subject: </b>[Python.NET] Wrap in interface (#1240)</p>
</div>
<p class=3D"x_MsoNormal">&nbsp;</p>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">Hell=
o,</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">This=
 <a href=3D"https://nam10.safelinks.protection.outlook.com/?url=3Dhttps%3A%=
2F%2Fgithub.com%2Fpythonnet%2Fpythonnet%2Fpull%2F1240&amp;data=3D04%7C01%7C=
mohamed.koubaa%40ansys.com%7C37b0dd3831f140993f6008d87fa1418f%7C34c6ce6715b=
84eff80e952da8be89706%7C0%7C0%7C637399677854765584%7CUnknown%7CTWFpbGZsb3d8=
eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&a=
mp;sdata=3DtTftofPt0a7ds4g1qBjLIBXi7iFOgtygMW3Xa3WHF%2Fo%3D&amp;reserved=3D=
0" originalsrc=3D"https://github.com/pythonnet/pythonnet/pull/1240" shash=
=3D"vyYsgvINGSLnbes6L+4y1TCDW2teH/FYnmyj7SFODfIeLPJzQgO6AGw063VtEJpo11HNOUx=
5cJm1Ma5L3JT0AEfBx4DoESrAQOVD38aWZKs9m3GDjW+LRuwAgaI6RhSn2MUCDYcA+OVRciE8Um=
F/KzufoAS32Xul+y3Zw9cj08E=3D" title=3D"https://github.com/pythonnet/pythonn=
et/pull/1240">
PR</a>&nbsp;changed behavior of pythonnet to use stricter typing when a met=
hod returns an interface.&nbsp; I'd like a way to opt-out of this behavior,=
 and I'll share a representative use-case below.&nbsp; The tl;dr is that py=
thon is a dynamic language and I expect the C#
 objects which pythonnet wraps to behave more like &quot;dynamic&quot; and =
less like the static types on the interface.</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">****=
 C# code ****</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">namespace Example1</span><span style=3D"fo=
nt-size:12.0pt; color:black">
</span></p>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">{</span><span style=3D"font-size:12.0pt; c=
olor:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; public enum ShapeType</span>=
<span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; {</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; Square,</span>=
<span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; Circle</span><=
span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; }</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; public interface IShape</spa=
n><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; {</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; void Draw();</=
span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; double Area { =
get; }</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; ShapeType Type=
 { get; }</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; }</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; public class Square : IShape=
</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; {</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public double =
Length { get; }</span><span style=3D"font-size:12.0pt; color:black"></span>=
</p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public Square(=
double length)</span><span style=3D"font-size:12.0pt; color:black"></span><=
/p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; {</span><span =
style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
Length =3D length;</span><span style=3D"font-size:12.0pt; color:black"></sp=
an></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; }</span><span =
style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public void Dr=
aw() {}</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public double =
Area { get { return Length * Length; } }</span><span style=3D"font-size:12.=
0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public ShapeTy=
pe Type { get { return ShapeType.Square; } }</span><span style=3D"font-size=
:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; }</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; public class Circle : IShape=
</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; {</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public double =
Radius { get; }</span><span style=3D"font-size:12.0pt; color:black"></span>=
</p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public Circle(=
double radius)</span><span style=3D"font-size:12.0pt; color:black"></span><=
/p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; {</span><span =
style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
Radius =3D radius;</span><span style=3D"font-size:12.0pt; color:black"></sp=
an></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; }</span><span =
style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public void Dr=
aw() {}</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public double =
Area { get { return Math.PI * Radius * Radius; } }</span><span style=3D"fon=
t-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public ShapeTy=
pe Type { get { return ShapeType.Circle; } }</span><span style=3D"font-size=
:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; }</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; public class ShapeDataModel<=
/span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; {</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; private Dictio=
nary&lt;int, IShape&gt; _shapes =3D new Dictionary&lt;int, IShape&gt;();</s=
pan><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; private int _n=
extId =3D 1;</span><span style=3D"font-size:12.0pt; color:black"></span></p=
>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public int Add=
Shape(IShape shape)</span><span style=3D"font-size:12.0pt; color:black"></s=
pan></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; {</span><span =
style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
int id =3D _nextId;</span><span style=3D"font-size:12.0pt; color:black"></s=
pan></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
_shapes[id] =3D shape;</span><span style=3D"font-size:12.0pt; color:black">=
</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
_nextId++;</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
return id;</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; }</span><span =
style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; public IShape =
GetShape(int id)</span><span style=3D"font-size:12.0pt; color:black"></span=
></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; {</span><span =
style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
return _shapes[id];</span><span style=3D"font-size:12.0pt; color:black"></s=
pan></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; &nbsp; &nbsp; }</span><span =
style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">&nbsp; &nbsp; }</span><span style=3D"font-=
size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black">}</span><span style=3D"font-size:12.0pt; c=
olor:black"></span></p>
</div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black">&nbs=
p;</span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black; back=
ground:#181A1B">**** Python code ****</span><span style=3D"font-size:12.0pt=
; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; import cl=
r</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; clr.AddRe=
ference(&quot;Example1&quot;)</span><span style=3D"font-size:12.0pt; color:=
black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; import Ex=
ample1</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; sq1 =3D E=
xample1.Square(2.)</span><span style=3D"font-size:12.0pt; color:black; back=
ground:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; ci1 =3D E=
xample1.Circle(1.3)</span><span style=3D"font-size:12.0pt; color:black; bac=
kground:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; sq2 =3D E=
xample1.Square(2.5)</span><span style=3D"font-size:12.0pt; color:black; bac=
kground:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; m =3D Exa=
mple1.ShapeDataModel()</span><span style=3D"font-size:12.0pt; color:black; =
background:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; m.AddShap=
e(sq1)</span><span style=3D"font-size:12.0pt; color:black; background:#1315=
16"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">1</span><span style=3D=
"font-size:12.0pt; color:black; background:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; m.AddShap=
e(sq2)</span><span style=3D"font-size:12.0pt; color:black; background:#1315=
16"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">2</span><span style=3D=
"font-size:12.0pt; color:black; background:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; m.AddShap=
e(ci1)</span><span style=3D"font-size:12.0pt; color:black; background:#1315=
16"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">3</span><span style=3D=
"font-size:12.0pt; color:black; background:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; m.GetShap=
e(2)</span><span style=3D"font-size:12.0pt; color:black; background:#131516=
"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&lt;Example1.IShape ob=
ject at 0x000002A3448A09A0&gt;</span><span style=3D"font-size:12.0pt; color=
:black; background:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; m.GetShap=
e(2).Area</span><span style=3D"font-size:12.0pt; color:black; background:#1=
31516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">6.25</span><span style=
=3D"font-size:12.0pt; color:black; background:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">&gt;&gt;&gt; m.GetShap=
e(2).Length</span><span style=3D"font-size:12.0pt; color:black; background:=
#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:black; background:#131516">Traceback (most recent=
 call last):</span><span style=3D"font-size:12.0pt; color:black; background=
:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:#ED5C57; background:#131516">&nbsp; File &quot;&l=
t;stdin&gt;&quot;, line 1, in &lt;module&gt;</span><span style=3D"font-size=
:12.0pt; color:black; background:#131516"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; font-family:&quot=
;Courier New&quot;; color:#ED5C57; background:#131516">AttributeError: 'ISh=
ape' object has no attribute 'Length'</span><span style=3D"font-size:12.0pt=
; color:black; background:#131516"></span></p>
</div>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black; back=
ground:#131516"><br>
<br>
</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black; back=
ground:#131516">**** summary ****</span><span style=3D"font-size:12.0pt; co=
lor:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black; back=
ground:#131516">This factory and/or datamodel pattern is very common in my =
codebase and probably also lots of object oriented systems.&nbsp; The menti=
oned PR breaks this common design pattern
 in C# objects wrapped by pythonnet, and I would like a way to opt-out of i=
t.&nbsp; Maybe an attribute on the method which returns an interface can be=
 used, or maybe something global to switch this behavior.&nbsp; I think per=
haps the original bug might also have been
 fixed in a different way.&nbsp;</span><span style=3D"font-size:12.0pt; col=
or:black"></span></p>
</div>
<div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black; back=
ground:#131516"><br>
<br>
</span><span style=3D"font-size:12.0pt; color:black"></span></p>
</div>
<p class=3D"x_MsoNormal"><span style=3D"font-size:12.0pt; color:black; back=
ground:#131516">Thanks!<br>
Mohamed</span><span style=3D"font-size:12.0pt; color:black"></span></p>
<p class=3D"x_MsoNormal">&nbsp;</p>
</div>
</div>
</div>
</body>
</html>

--_000_SN6PR01MB4976CCEE1E29E0FC89CE0CC8998F9SN6PR01MB4976prod_--

--===============4369368159843712820==
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]

--===============4369368159843712820==--