[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/achernet/pythonnet/develop/src/runtime/constructorbinder.cs [Back]  [Original]

// ==========================================================================
// This software is subject to the provisions of the Zope Public License,
// Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE.
// ==========================================================================

using System;
using System.Reflection;

namespace Python.Runtime {

    //========================================================================
    // A ConstructorBinder encapsulates information about one or more managed
    // constructors, and is responsible for selecting the right constructor
    // given a set of Python arguments. This is slightly different than the
    // standard MethodBinder because of a difference in invoking constructors
    // using reflection (which is seems to be a CLR bug).
    //========================================================================

    internal class ConstructorBinder : MethodBinder {

        internal ConstructorBinder () : base() {}

        //====================================================================
        // Constructors get invoked when an instance of a wrapped managed
        // class or a subclass of a managed class is created. This differs
        // from the MethodBinder implementation in that we return the raw
        // result of the constructor rather than wrapping it as a Python 
        // object - the reason is that only the caller knows the correct
        // Python type to use when wrapping the result (may be a subclass).
        //====================================================================

        internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw) {
            return this.InvokeRaw(inst, args, kw, null);
        }
        /// 
        /// Allows ctor selection to be limited to a single attempt at a
        /// match by providing the MethodBase to use instead of searching
        /// the entire MethodBinder.list (generic ArrayList)
        /// 
        ///  (possibly null) instance 
        ///  PyObject* to the arg tuple 
        ///  PyObject* to the keyword args dict 
        ///  The sole ContructorInfo to use or null 
        ///  The result of the constructor call with converted params 
        /// 
        /// 2010-07-24 BC: I added the info parameter to the call to Bind()
        /// Binding binding = this.Bind(inst, args, kw, info);
        /// to take advantage of Bind()'s ability to use a single MethodBase (CI or MI).
        /// 
        internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw,
                                  MethodBase info) {
            Binding binding = this.Bind(inst, args, kw, info);
            Object result;

            if (binding == null) {
                // It is possible for __new__ to be invoked on construction
                // of a Python subclass of a managed class, so args may
                // reflect more args than are required to instantiate the
                // class. So if we cant find a ctor that matches, we'll see
                // if there is a default constructor and, if so, assume that
                // any extra args are intended for the subclass' __init__.

                IntPtr eargs = Runtime.PyTuple_New(0);
                binding = this.Bind(inst, eargs, kw);
                Runtime.Decref(eargs);

                if (binding == null) {
                    Exceptions.SetError(Exceptions.TypeError,
                                        "no constructor matches given arguments"
                                        );
                    return null;
                }
            }

            // Fire the selected ctor and catch errors...
            ConstructorInfo ci = (ConstructorInfo)binding.info;
            // Object construction is presumed to be non-blocking and fast
            // enough that we shouldn't really need to release the GIL.
            try {
                result = ci.Invoke(binding.args);
            }
            catch (Exception e) {
                if (e.InnerException != null) {
                    e = e.InnerException;
                }
                Exceptions.SetError(e);
                return null;
            }
            return result;
        }
    }
}

Web Proxy Viewer  |  New URL  |  Original Page