[Python.NET] Subclassing CLR types

Michael Amrhein Michael.Amrhein at t-online.de
Thu Oct 30 17:48:39 EST 2003


Hi,
subclassing CLR types does work as long as you hold a reference to the 
instance of the subclass in Python. But when you pass a subclassed 
object to a CLR object and retrieve this object later through a method 
of the CLR object you don't get an instance of the subclass but an 
instance of the CLR base class the subclass was derived from:

Python 2.3.2 (#49, Oct  2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on 
win32
Type "help", "copyright", "credits" or "license" for more information.
 >>> import CLR
 >>> from CLR.System.Windows.Forms import Control
 >>> c=Control("This is a Control.")
 >>> class myControl(Control):
...     def dummy(self):
...             return self.Text
...
 >>> m=myControl(c, "This is a myControl.")
 >>> m.Parent
<CLR.System.Windows.Forms.Control object at 0x008F6F70>
 >>> m.Parent.Text
u'This is a Control.'
 >>> c.Contains(m)
True
 >>> m.dummy()
u'This is a myControl.'
 >>> c.Controls[0] == m
True

[Every thing ok, so far, but ...]

 >>> c.Controls[0].dummy()
Traceback (most recent call last):
   File "<stdin>", line 1, in ?
AttributeError: 'Control' object has no attribute 'dummy'

[Because ...]

 >>> type(c.Controls[0])
<class 'CLR.System.Windows.Forms.Control'>

This is weird because it means that when I get back an instance of a 
subclass from some CLR method I don't know the correct type and can not 
act on it properly.

I don't know if there's an easy way to come around this problem but to 
me subclassing of CLR types seemes pretty useless without a solution for it.

If there is some kind of unique reference from the Python wrapper 
instances to the CLR instances a starting point for a solution may be to 
base all wrappers on a base type which keeps a mapping of referenced CLR 
instances to wrapper instances.

Something like this (all not tested yet!!!):

class CLRObj(object):

     from weakref import WeakValueDictionary

     __objMap = WeakValueDictionary()

     def __new__(cls, ref):
         try:
             obj = clrObj.__objMap[ref]
         except KeyError:
             obj = object.__new__(cls)
             obj._ref = ref
             clrObj.__objMap[ref] = obj
         return obj

     def __del__(self):
         self._ref.Dispose()

class <wrapper>(CLRObj):

     def __new__(cls, ...):
         ref = <create base CLR type>
         return CLRObj.__new__(cls, ref)

... and when receiving a CLR instance turn it into the corresponding 
wrapper instance by

obj = CLRObj(clrObj)

This will not work if you receive some kind of CLR object which was 
created internally by some CLR method and not through a wrapper. But you 
will get all object you created through the wrappers back as instances 
of the correct type.

If I'm galloping in the wrong direction please give me a short stop 
signal. If not ... lets figure out the probably missing details.

Michael




More information about the PythonDotNet mailing list