[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/chid/pythonnet/master/pythonnet/src/runtime/methodobject.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.Collections;
using System.Reflection;

namespace Python.Runtime {

    //========================================================================
    // Implements a Python type that provides access to CLR object methods.
    //========================================================================

    internal class MethodObject : ExtensionType {

	internal MethodInfo[] info;
	internal string name;
	internal MethodBinding unbound;
	internal MethodBinder binder;
	internal IntPtr doc;

	public MethodObject(string name, MethodInfo[] info) : base() {
	    this.name = name;
	    this.info = info;
	    binder = new MethodBinder();
	    for (int i = 0; i < info.Length; i++) {
		binder.AddMethod((MethodInfo)info[i]);
	    }
	}


	public virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) {
	    return this.Invoke(inst, args, kw, null);
	}
 
	public virtual IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw,
				     MethodBase info) {
	    return binder.Invoke(target, args, kw, info);
	}


	//====================================================================
	// Helper to get docstrings from reflected method / param info.
	//====================================================================

	internal IntPtr GetDocString() {
	    if (doc != IntPtr.Zero) {
		return doc;
	    }
	    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();
	    }
	    doc = Runtime.PyString_FromString(str);
	    return doc;
	}


	//====================================================================
	// This is a little tricky: a class can actually have a static method
	// and instance methods all with the same name. That makes it tough
	// to support calling a method 'unbound' (passing the instance as the
	// first argument), because in this case we can't know whether to call
	// the instance method unbound or call the static method. 
	//
	// The rule we is that if there are both instance and static methods
	// with the same name, then we always call the static method. So this
	// method returns true if any of the methods that are represented by 
	// the descriptor are static methods (called by MethodBinding).
	//====================================================================

	internal bool IsStatic() {
	    MethodBase[] methods = binder.GetMethods();
	    for (int i = 0; i < methods.Length; i++) {
		if (methods[i].IsStatic)
		    return true;
	    }
	    return false;
	}


	//====================================================================
	// Descriptor __getattribute__ implementation. 
	//====================================================================

	[CallConvCdecl()]
	public static IntPtr tp_getattro(IntPtr ob, IntPtr key) {
	    MethodObject self = (MethodObject)GetManagedObject(ob);

	    if (!Runtime.PyString_Check(key)) {
		return Exceptions.RaiseTypeError("string expected");
	    }

	    string name = Runtime.GetManagedString(key);
	    if (name == "__doc__") {
		IntPtr doc = self.GetDocString();
		Runtime.Incref(doc);
		return doc;
	    }

	    return Runtime.PyObject_GenericGetAttr(ob, key);
	}


	//====================================================================
	// Descriptor __get__ implementation. Accessing a CLR method returns
	// a "bound" method similar to a Python bound method. 
	//====================================================================

	[CallConvCdecl()]
	public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) {
	    MethodObject self = (MethodObject)GetManagedObject(ds);
	    MethodBinding binding;

	    // If the method is accessed through its type (rather than via
	    // an instance) we return an 'unbound' MethodBinding that will
	    // cached for future accesses through the type.

	    if (ob == IntPtr.Zero) {
		if (self.unbound == null) {
		    self.unbound = new MethodBinding(self, IntPtr.Zero);
		}
		binding = self.unbound;
		Runtime.Incref(binding.pyHandle);;
		return binding.pyHandle;
	    }

	    if (Runtime.PyObject_IsInstance(ob, tp) < 1) {
		return Exceptions.RaiseTypeError("invalid argument");
	    }

	    binding = new MethodBinding(self, ob);
	    return binding.pyHandle;
	}

	//====================================================================
	// Descriptor __repr__ implementation.
	//====================================================================

	[CallConvCdecl()]
	public static IntPtr tp_repr(IntPtr ob) {
	    MethodObject self = (MethodObject)GetManagedObject(ob);
	    string s = String.Format("", self.name);
	    return Runtime.PyString_FromStringAndSize(s, s.Length);
	}

	//====================================================================
	// Descriptor dealloc implementation.
	//====================================================================

	[CallConvCdecl()]
	public static new void tp_dealloc(IntPtr ob) {
	    MethodObject self = (MethodObject)GetManagedObject(ob);
	    Runtime.Decref(self.doc);
	    if (self.unbound != null) {
		Runtime.Decref(self.unbound.pyHandle);
	    }
	    ExtensionType.FinalizeObject(self);
	}


    }


}

Web Proxy Viewer  |  New URL  |  Original Page