This repository was archived by the owner on Jul 22, 2023. It is now read-only.
forked from pythonnet/pythonnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconstructorbinder.cs
More file actions
131 lines (120 loc) · 5.29 KB
/
constructorbinder.cs
File metadata and controls
131 lines (120 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
using System;
using System.Reflection;
using System.Text;
namespace Python.Runtime
{
/// <summary>
/// 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).
/// </summary>
[Serializable]
internal class ConstructorBinder : MethodBinder
{
private Type _containingType;
internal ConstructorBinder(Type containingType)
{
_containingType = containingType;
}
/// <summary>
/// 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).
/// </summary>
internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw)
{
return InvokeRaw(inst, args, kw, null);
}
/// <summary>
/// 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)
/// </summary>
/// <param name="inst"> (possibly null) instance </param>
/// <param name="args"> PyObject* to the arg tuple </param>
/// <param name="kw"> PyObject* to the keyword args dict </param>
/// <param name="info"> The sole ContructorInfo to use or null </param>
/// <returns> The result of the constructor call with converted params </returns>
/// <remarks>
/// 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).
/// </remarks>
internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info)
{
object result;
if (_containingType.IsValueType && !_containingType.IsPrimitive &&
!_containingType.IsEnum && _containingType != typeof(decimal) &&
Runtime.PyTuple_Size(args) == 0)
{
// If you are trying to construct an instance of a struct by
// calling its default constructor, that ConstructorInfo
// instance will not appear in reflection and the object must
// instead be constructed via a call to
// Activator.CreateInstance().
try
{
result = Activator.CreateInstance(_containingType);
}
catch (Exception e)
{
if (e.InnerException != null)
{
e = e.InnerException;
}
Exceptions.SetError(e);
return null;
}
return result;
}
Binding binding = Bind(inst, args, kw, info);
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 = Bind(inst, eargs, IntPtr.Zero);
Runtime.XDecref(eargs);
if (binding == null)
{
var errorMessage = new StringBuilder("No constructor matches given arguments");
if (info != null && info.IsConstructor && info.DeclaringType != null)
{
errorMessage.Append(" for ").Append(info.DeclaringType.Name);
}
errorMessage.Append(": ");
AppendArgumentTypes(to: errorMessage, args);
Exceptions.SetError(Exceptions.TypeError, errorMessage.ToString());
return null;
}
}
// Fire the selected ctor and catch errors...
var 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;
}
}
}