[IronPython] Monkey-patching CLR types

Jimmy Schementi Jimmy.Schementi at microsoft.com
Tue Feb 16 04:08:06 CET 2010


Thanks Dino!

I've got something to at least compile, but I'm getting the error "ArgumentTypeException: unsupported operand type(s) for +=: 'PythonBrowserEvent' and 'function'". OK, makes sense, it's not finding InPlaceAdd(Python.Runtime.Method), right? Since I can't link against IronPython, what type should I use instead of Python.Runtime.Method? System.Dynamic.IDynamicMetaObjectProvider, as that's the only DLR interface that Method implements? If so, then I'm not sure how to convert it to an Action<object, HtmlEventArgs>.

Also, should I be using "op_AdditionAssignment" instead of InPlaceAdd? The usage in ReflectedEvent.cs (http://ironpython.codeplex.com/sourcecontrol/changeset/view/63991?projectName=IronPython#384571) seems to say that.

If it helps, here's what I have so far:

    public static class HtmlElementExtension {
        [SpecialName]
        public static object GetBoundMember(HtmlElement element, string name) {
            object propertyValue = element.GetProperty(name);
            // No way to tell if a property actually exists, so best we can do
            // do is check if it's null ...
            if (propertyValue == null) {
                return new PythonBrowserEvent(element, name);
            }
            return propertyValue;
        }
    }

    public class PythonBrowserEvent {
        private readonly HtmlElement _element;
        private readonly string _event;

        internal PythonBrowserEvent(HtmlElement element, string eventStr) {
            _element = element;
            _event = eventStr;
        }

        [SpecialName]
        public object InPlaceAdd(object handler) {
            _element.AttachEvent(_event, 
                new EventHandler<HtmlEventArgs>((Action<object, HtmlEventArgs>)handler));
            return null;
        }
    }

> -----Original Message-----
> From: users-bounces at lists.ironpython.com [mailto:users-
> bounces at lists.ironpython.com] On Behalf Of Dino Viehland
> Sent: Sunday, February 14, 2010 4:58 PM
> To: Discussion of IronPython
> Subject: Re: [IronPython] Monkey-patching CLR types
> 
> You can define an extension property that gets/sets a value which supports in
> place addition / subtraction.  Something like this:
> 
>     [assembly: ExtensionType(typeof(HtmlElement),
> typeof(HtmlElementExtension))]
>     public static class HtmlElementExtension {
>         [SpecialName, PropertyMethod]
>         public static MyEvent Getonclick(HtmlElement element) {
>              return new MyEvent(element);
>         }
>         [SpecialName, PropertyMethod]
>         public static void Setonclick(HtmlElement element, object value) {
> 		// You could return a value from InPlaceAdd and validate it
> here
> 		// to report an error on a direct assignment - this is what
> 		// ReflectedEvent does in IronPython.
>         }
>     }
> 
>     public class MyEvent {
>          private readonly HtmlElement _element;
> 	   public MyEvent(HtmlElement element) {
>               _element = element;
>          }
> 	   [SpecialName]
>          public object InPlaceAdd(EventHandler[HtmlEventArgs] handler) {
>               _element.AttachEvent("onclick", handler);
> 		  return null;
>          }
> 	   // also needs InPlaceSubtract
>     }
> 
> -----Original Message-----
> From: users-bounces at lists.ironpython.com [mailto:users-
> bounces at lists.ironpython.com] On Behalf Of Jimmy Schementi
> Sent: Sunday, February 14, 2010 2:06 PM
> To: Discussion of IronPython
> Subject: [IronPython] Monkey-patching CLR types
> 
> (Yes, I'm asking a question this time =P)
> 
> I want to know my options for adding functionality to an existing CLR type.
> Specifically I want to make hooking DOM events cleaner: in Silverlight today
> you cannot hook DOM events with the standard += syntax that IronPython uses
> for CLR events:
> 
>     object.onclick += foo
> 
> Instead you must do this:
> 
>     object.AttachEvent("onclick", EventHandler[HtmlEventArgs](foo))
> 
> In IronRuby I fixed that by just monkey-patching
> System.Windows.Browser.HtmlObject, but in IronPython I cannot monkey-patch
> built-in types. However, I do something similar with accessing DOM properties
> (instead of element.GetProperty("innerHTML") it's just element.innerHTML)
> with DLR's ExtensionType, which is the same way IronPython exposes special
> methods on CLR types as well:
> 
>     [assembly: ExtensionType(typeof(HtmlElement),
> typeof(HtmlElementExtension))]
>     public static class HtmlElementExtension {
>         [SpecialName]
>         public static object GetBoundMember(HtmlElement element, string name)
> {
>             return element.GetProperty(name);
>         }
>     }
> 
> But after looking through Python's Binder and the DLR's ActionBinder for how
> they use ExtensionTypes, I couldn't get a definitive answer on how to capture
> an method call plus an operator. Any ideas?
> 
> ~Jimmy
> 
> _______________________________________________
> Users mailing list
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> _______________________________________________
> Users mailing list
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com




More information about the Ironpython-users mailing list