From 7db46e5dbf1993caaca7f20ff4cc4828ce98ace7 Mon Sep 17 00:00:00 2001 From: Luke Stratman Date: Sat, 31 Jan 2015 09:51:52 -0500 Subject: [PATCH 1/2] A struct's default constructor can now be called to create an object instance (via Activator.CreateInstance()) instead of having to be forced to implement an explicit constructor on the struct. --- src/runtime/classobject.cs | 2 +- src/runtime/constructorbinder.cs | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/runtime/classobject.cs b/src/runtime/classobject.cs index c331637be..5e79e8253 100644 --- a/src/runtime/classobject.cs +++ b/src/runtime/classobject.cs @@ -26,7 +26,7 @@ internal class ClassObject : ClassBase { internal ClassObject(Type tp) : base(tp) { ctors = type.GetConstructors(); - binder = new ConstructorBinder(); + binder = new ConstructorBinder(type); for (int i = 0; i < ctors.Length; i++) { binder.AddMethod(ctors[i]); diff --git a/src/runtime/constructorbinder.cs b/src/runtime/constructorbinder.cs index 4dc1f1457..82be07e1f 100644 --- a/src/runtime/constructorbinder.cs +++ b/src/runtime/constructorbinder.cs @@ -21,8 +21,11 @@ namespace Python.Runtime { //======================================================================== internal class ConstructorBinder : MethodBinder { + private Type _containingType = null; - internal ConstructorBinder () : base() {} + internal ConstructorBinder(Type containingType) : base() { + _containingType = containingType; + } //==================================================================== // Constructors get invoked when an instance of a wrapped managed @@ -53,9 +56,31 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw) { /// internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info) { - Binding binding = this.Bind(inst, args, kw, 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 = this.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 From 403b60d0084574fdd57a2412fba9d35ab6411e24 Mon Sep 17 00:00:00 2001 From: Luke Stratman Date: Sat, 31 Jan 2015 11:17:21 -0500 Subject: [PATCH 2/2] Updated the tests to reflect that a struct's default constructor can now be invoked. --- src/tests/test_class.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/tests/test_class.py b/src/tests/test_class.py index ecc335999..b87587586 100644 --- a/src/tests/test_class.py +++ b/src/tests/test_class.py @@ -130,10 +130,9 @@ def testStructConstruction(self): """Test construction of structs.""" from System.Drawing import Point - def test(): - p = Point() - - self.assertRaises(TypeError, test) + p = Point() + self.assertTrue(p.X == 0) + self.assertTrue(p.Y == 0) p = Point(0, 0) self.assertTrue(p.X == 0)