[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/danic/pythonnet/develop/src/runtime/classobject.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 {

    /// 
    /// Managed class that provides the implementation for reflected types.
    /// Managed classes and value types are represented in Python by actual 
    /// Python type objects. Each of those type objects is associated with 
    /// an instance of ClassObject, which provides its implementation.
    /// 

    internal class ClassObject : ClassBase {

        internal ConstructorBinder binder;
        internal ConstructorInfo[] ctors;

        internal ClassObject(Type tp) : base(tp) {
            ctors = type.GetConstructors();
            binder = new ConstructorBinder(type);

            for (int i = 0; i < ctors.Length; i++) {
                binder.AddMethod(ctors[i]);
            }
        }


        //====================================================================
        // Helper to get docstring from reflected constructor info.
        //====================================================================

        internal IntPtr GetDocString() {
            MethodBase[] methods = binder.GetMethods();
            string str = "";
            for (int i = 0; i < methods.Length; i++) {
                if (str.Length > 0)
                    str += Environment.NewLine;
                str += methods[i].ToString();
            }
            return Runtime.PyString_FromString(str);
        }


        //====================================================================
        // Implements __new__ for reflected classes and value types.
        //====================================================================

        public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {

            ClassObject self = GetManagedObject(tp) as ClassObject;

            // Sanity check: this ensures a graceful error if someone does
            // something intentially wrong like use the managed metatype for
            // a class that is not really derived from a managed class.

            if (self == null) {
                return Exceptions.RaiseTypeError("invalid object");
            }
            
            Type type = self.type;

            // Primitive types do not have constructors, but they look like
            // they do from Python. If the ClassObject represents one of the 
            // convertible primitive types, just convert the arg directly.

            if (type.IsPrimitive || type == typeof(String)) {
                if (Runtime.PyTuple_Size(args) != 1) {
                    Exceptions.SetError(Exceptions.TypeError, 
                               "no constructors match given arguments"
                               );
                    return IntPtr.Zero;
                }

                IntPtr op = Runtime.PyTuple_GetItem(args, 0);
                Object result;

                if (!Converter.ToManaged(op, type, out result, true)) {
                    return IntPtr.Zero;
                }

                return CLRObject.GetInstHandle(result, tp);
            }

            if (type.IsAbstract) {
                Exceptions.SetError(Exceptions.TypeError, 
                           "cannot instantiate abstract class"
                           );
                return IntPtr.Zero;
            }

            if (type.IsEnum) {
                Exceptions.SetError(Exceptions.TypeError, 
                           "cannot instantiate enumeration"
                           );
                return IntPtr.Zero;
            }

            Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw);
            if (obj == null) {
                return IntPtr.Zero;
            }

            return CLRObject.GetInstHandle(obj, tp);
        }


         //====================================================================
         // Implementation of [] semantics for reflected types. This exists 
         // both to implement the Array[int] syntax for creating arrays and 
        // to support generic name overload resolution using [].
         //====================================================================
 
         public override IntPtr type_subscript(IntPtr idx) {

            // If this type is the Array type, the [] means we need to
            // construct and return an array type of the given element type.

             if ((this.type) == typeof(Array)) {
                if (Runtime.PyTuple_Check(idx)) {
                    return Exceptions.RaiseTypeError("type expected");
                }
                ClassBase c = GetManagedObject(idx) as ClassBase;
                Type t = (c != null) ? c.type : Converter.GetTypeByAlias(idx);
                if (t == null) {
                    return Exceptions.RaiseTypeError("type expected");
                }
                Type a = t.MakeArrayType();
                ClassBase o = ClassManager.GetClass(a);
                Runtime.Incref(o.pyHandle);
                return o.pyHandle;         
            }   

            // If there are generics in our namespace with the same base name
            // as the current type, then [] means the caller wants to
            // bind the generic type matching the given type parameters.

            Type[] types = Runtime.PythonArgsToTypeArray(idx);
            if (types == null) {
                return Exceptions.RaiseTypeError("type(s) expected");
            }

            string gname = this.type.FullName + "`" + types.Length.ToString();
            Type gtype = AssemblyManager.LookupType(gname);
            if (gtype != null) {
                GenericType g = ClassManager.GetClass(gtype) as GenericType;
                return g.type_subscript(idx);
                /*Runtime.Incref(g.pyHandle);
                return g.pyHandle;*/
            }
            return Exceptions.RaiseTypeError("unsubscriptable object");
         }
 

        //====================================================================
        // Implements __getitem__ for reflected classes and value types.
        //====================================================================

        public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) {
            //ManagedType self = GetManagedObject(ob);
            IntPtr tp = Runtime.PyObject_TYPE(ob);
            ClassBase cls = (ClassBase)GetManagedObject(tp);

            if (cls.indexer == null || !cls.indexer.CanGet) {
                Exceptions.SetError(Exceptions.TypeError, 
                                    "unindexable object"
                                    );
                return IntPtr.Zero;
            }

            // Arg may be a tuple in the case of an indexer with multiple
            // parameters. If so, use it directly, else make a new tuple
            // with the index arg (method binders expect arg tuples).

            IntPtr args = idx;
            bool free = false;

            if (!Runtime.PyTuple_Check(idx)) {
                args = Runtime.PyTuple_New(1);
                Runtime.Incref(idx);
                Runtime.PyTuple_SetItem(args, 0, idx);
                free = true;
            }

            IntPtr value = IntPtr.Zero;

            try {
                value = cls.indexer.GetItem(ob, args);
            }
            finally {
                if (free) {
                    Runtime.Decref(args);
                }
            }
            return value;
        }


        //====================================================================
        // Implements __setitem__ for reflected classes and value types.
        //====================================================================

        public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
            //ManagedType self = GetManagedObject(ob);
            IntPtr tp = Runtime.PyObject_TYPE(ob);
            ClassBase cls = (ClassBase)GetManagedObject(tp);

            if (cls.indexer == null || !cls.indexer.CanSet) {
                Exceptions.SetError(Exceptions.TypeError, 
                                    "object doesn't support item assignment"
                                    );
                return -1;
            }

            // Arg may be a tuple in the case of an indexer with multiple
            // parameters. If so, use it directly, else make a new tuple
            // with the index arg (method binders expect arg tuples).
            IntPtr args = idx;
            bool free = false;

            if (!Runtime.PyTuple_Check(idx)) {
                args = Runtime.PyTuple_New(1);
                Runtime.Incref(idx);
                Runtime.PyTuple_SetItem(args, 0, idx);
                free = true;
            }

            // Get the args passed in.
            int i = Runtime.PyTuple_Size(args);
            IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
            int numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
            int temp = i + numOfDefaultArgs;
            IntPtr real = Runtime.PyTuple_New(temp + 1);
            for (int n = 0; n < i; n++) {
                IntPtr item = Runtime.PyTuple_GetItem(args, n);
                Runtime.Incref(item);
                Runtime.PyTuple_SetItem(real, n, item);
            }

            // Add Default Args if needed
            for (int n = 0; n < numOfDefaultArgs; n++) {
                IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
                Runtime.Incref(item);
                Runtime.PyTuple_SetItem(real, n + i, item);
            }
            // no longer need defaultArgs 
            Runtime.Decref(defaultArgs);
            i = temp;

            // Add value to argument list
            Runtime.Incref(v);
            Runtime.PyTuple_SetItem(real, i, v);

            try {
                cls.indexer.SetItem(ob, real);
            }
            finally {
                Runtime.Decref(real);

                if (free) {
                    Runtime.Decref(args);
                }
            }

            if (Exceptions.ErrorOccurred()) {
                return -1;
            }

            return 0;
        }


        //====================================================================
        // This is a hack. Generally, no managed class is considered callable
        // from Python - with the exception of System.Delegate. It is useful
        // to be able to call a System.Delegate instance directly, especially
        // when working with multicast delegates.
        //====================================================================

        public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
            //ManagedType self = GetManagedObject(ob);
            IntPtr tp = Runtime.PyObject_TYPE(ob);
            ClassBase cb = (ClassBase)GetManagedObject(tp);

            if (cb.type != typeof(System.Delegate)) {
                Exceptions.SetError(Exceptions.TypeError, 
                                    "object is not callable");
                return IntPtr.Zero;
            }

            CLRObject co = (CLRObject)ManagedType.GetManagedObject(ob);
            Delegate d = co.inst as Delegate;
            BindingFlags flags = BindingFlags.Public | 
                                 BindingFlags.NonPublic |
                                 BindingFlags.Instance |
                                 BindingFlags.Static;

            MethodInfo method = d.GetType().GetMethod("Invoke", flags);
              MethodBinder binder = new MethodBinder(method);
             return binder.Invoke(ob, args, kw);
        }


    }        

}

Web Proxy Viewer  |  New URL  |  Original Page