diff --git a/src/Mono.VisualC.Interop/ABI/CppAbi.cs b/src/Mono.VisualC.Interop/ABI/CppAbi.cs index ff705983..6fce1cd8 100644 --- a/src/Mono.VisualC.Interop/ABI/CppAbi.cs +++ b/src/Mono.VisualC.Interop/ABI/CppAbi.cs @@ -225,7 +225,7 @@ namespace Mono.VisualC.Interop.ABI { if (!isStatic) { if (psig.ParameterTypes.Count == 0) - throw new ArgumentException ("First argument to non-static C++ method must be IntPtr or CppInstancePtr."); + throw new ArgumentException ("First argument to non-static C++ method must be instance pointer."); // 2. Load the native C++ instance pointer EmitLoadInstancePtr (il, interfaceMethod.GetParameters () [0].ParameterType, out cppInstancePtr, out nativePtr); @@ -237,7 +237,7 @@ namespace Mono.VisualC.Interop.ABI { MethodInfo nativeMethod; if (IsVirtual (interfaceMethod) && psig.Type != MethodType.NativeDtor) { - nativeMethod = EmitPrepareVirtualCall (il, typeInfo, nativePtr, vtableIndex++); + nativeMethod = EmitPrepareVirtualCall (il, typeInfo, cppInstancePtr, vtableIndex++); } else { if (IsVirtual (interfaceMethod)) vtableIndex++; @@ -247,7 +247,7 @@ namespace Mono.VisualC.Interop.ABI { switch (psig.Type) { case MethodType.NativeCtor: - EmitConstruct (il, nativeMethod, psig, nativePtr); + EmitConstruct (il, nativeMethod, psig, cppInstancePtr, nativePtr); break; case MethodType.NativeDtor: EmitDestruct (il, nativeMethod, psig, cppInstancePtr, nativePtr); @@ -447,15 +447,16 @@ namespace Mono.VisualC.Interop.ABI { * Emits the IL to load the correct delegate instance and/or retrieve the MethodInfo from the VTable * for a C++ virtual call. */ - protected virtual MethodInfo EmitPrepareVirtualCall (ILGenerator il, CppTypeInfo typeInfo, LocalBuilder native, int vtableIndex) + protected virtual MethodInfo EmitPrepareVirtualCall (ILGenerator il, CppTypeInfo typeInfo, + LocalBuilder cppInstancePtr, int vtableIndex) { Type vtableDelegateType = typeInfo.VTableDelegateTypes [vtableIndex]; MethodInfo getDelegate = typeinfo_adjvcall.MakeGenericMethod (vtableDelegateType); - // this._typeInfo.GetAdjustedVirtualCall (native, vtableIndex); + // this._typeInfo.GetAdjustedVirtualCall (cppInstancePtr, vtableIndex); il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldfld, typeinfo_field); - il.Emit (OpCodes.Ldloc_S, native); + il.Emit (OpCodes.Ldloc_S, cppInstancePtr); il.Emit (OpCodes.Ldc_I4, vtableIndex); il.Emit (OpCodes.Callvirt, getDelegate); @@ -481,11 +482,19 @@ namespace Mono.VisualC.Interop.ABI { il.Emit (OpCodes.Newobj, cppip_fromsize); } - protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) + protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, + LocalBuilder cppInstancePtr, LocalBuilder nativePtr) { Debug.Assert (psig.Type == MethodType.NativeCtor); EmitNativeCall (il, nativeMethod, psig, nativePtr); - EmitInitVTable (il, nativePtr); + + if (cppInstancePtr != null && psig.OrigMethod.ReturnType == typeof (CppInstancePtr)) { + EmitInitVTable (il, cppInstancePtr); + il.Emit (OpCodes.Ldloc_S, cppInstancePtr); + + } else if (psig.OrigMethod.DeclaringType.GetInterfaces ().Any (i => i.IsGenericType && i.GetGenericTypeDefinition () == typeof (ICppClassOverridable<>))) { + throw new InvalidProgramException ("In ICppClassOverridable, native constructors must take as first argument and return CppInstancePtr"); + } } protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, @@ -497,19 +506,10 @@ namespace Mono.VisualC.Interop.ABI { if (cppInstancePtr == null) return; - // bail if we weren't alloc'd by managed code - Label bail = il.DefineLabel (); + EmitCheckManagedAlloc (il, cppInstancePtr); - il.Emit (OpCodes.Ldloca_S, cppInstancePtr); - il.Emit (OpCodes.Brfalse_S, bail); // <- FIXME? (would this ever branch?) - il.Emit (OpCodes.Ldloca_S, cppInstancePtr); - il.Emit (OpCodes.Call, cppip_managedalloc); - il.Emit (OpCodes.Brfalse_S, bail); - - EmitResetVTable (il, nativePtr); + EmitResetVTable (il, cppInstancePtr); EmitNativeCall (il, nativeMethod, psig, nativePtr); - - il.MarkLabel (bail); } /** @@ -538,12 +538,14 @@ namespace Mono.VisualC.Interop.ABI { il.Emit (OpCodes.Call, nativeMethod); // Marshal return value - EmitInboundMarshal (il, psig.ReturnType, interfaceMethod.ReturnType); + if (psig.Type != MethodType.NativeCtor) + EmitInboundMarshal (il, psig.ReturnType, interfaceMethod.ReturnType); } public virtual PInvokeSignature GetPInvokeSignature (MethodInfo method) { + var methodType = GetMethodType (method); var parameters = method.GetParameters (); var pinvokeTypes = new List (parameters.Length); @@ -554,10 +556,11 @@ namespace Mono.VisualC.Interop.ABI { return new PInvokeSignature { OrigMethod = method, Name = GetMangledMethodName (method), - Type = GetMethodType (method), + Type = methodType, CallingConvention = GetCallingConvention (method), ParameterTypes = pinvokeTypes, - ReturnType = ToPInvokeType (method.ReturnType, method.ReturnTypeCustomAttributes) + ReturnType = methodType == MethodType.NativeCtor? typeof (void) : + ToPInvokeType (method.ReturnType, method.ReturnTypeCustomAttributes) }; } @@ -770,19 +773,19 @@ namespace Mono.VisualC.Interop.ABI { * Emits IL to set the vtable pointer of the instance (if class has a vtable). * This should usually happen in the managed wrapper of the C++ instance constructor. */ - protected virtual void EmitInitVTable (ILGenerator il, LocalBuilder nativePtr) + protected virtual void EmitInitVTable (ILGenerator il, LocalBuilder cppip) { - // this._typeInfo.VTable.InitInstance (nativePtr); + // this._typeInfo.VTable.InitInstance (cppInstancePtr); EmitLoadVTable (il); - il.Emit (OpCodes.Ldloc_S, nativePtr); + il.Emit (OpCodes.Ldloca_S, cppip); EmitCallVTableMethod (il, vtable_initinstance, 2, false); } - protected virtual void EmitResetVTable (ILGenerator il, LocalBuilder nativePtr) + protected virtual void EmitResetVTable (ILGenerator il, LocalBuilder cppip) { - // this._typeInfo.VTable.ResetInstance (nativePtr); + // this._typeInfo.VTable.ResetInstance (cppInstancePtr); EmitLoadVTable (il); - il.Emit (OpCodes.Ldloc_S, nativePtr); + il.Emit (OpCodes.Ldloc_S, cppip); EmitCallVTableMethod (il, vtable_resetinstance, 2, false); } @@ -859,7 +862,7 @@ namespace Mono.VisualC.Interop.ABI { // if not, return Label managedAlloc = il.DefineLabel (); il.Emit (OpCodes.Ldloca_S, cppip); - il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ()); + il.Emit (OpCodes.Call, cppip_managedalloc); il.Emit (OpCodes.Brtrue_S, managedAlloc); il.Emit (OpCodes.Ret); il.MarkLabel (managedAlloc); diff --git a/src/Mono.VisualC.Interop/ABI/VTable.cs b/src/Mono.VisualC.Interop/ABI/VTable.cs index 42f6eb19..caabae08 100644 --- a/src/Mono.VisualC.Interop/ABI/VTable.cs +++ b/src/Mono.VisualC.Interop/ABI/VTable.cs @@ -27,6 +27,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System; +using System.Diagnostics; using System.Collections.Generic; using System.Reflection; @@ -34,14 +35,14 @@ using System.Reflection.Emit; using System.Runtime.InteropServices; namespace Mono.VisualC.Interop.ABI { - public delegate VTable MakeVTableDelegate (CppTypeInfo metadata); // TODO: RTTI .. support virtual inheritance - public abstract class VTable : IDisposable { - public static MakeVTableDelegate DefaultImplementation = VTableManaged.Implementation; + public class VTable : IDisposable { + + protected bool initialized; protected CppTypeInfo typeInfo; - protected IntPtr basePtr, vtPtr; + protected IntPtr vtPtr; public virtual int EntryCount { get { return typeInfo.VirtualMethods.Count; } @@ -50,12 +51,13 @@ namespace Mono.VisualC.Interop.ABI { get { return Marshal.SizeOf (typeof (IntPtr)); } } - public abstract T GetVirtualCallDelegate (IntPtr native, int vtableIndex) where T : class; /*Delegate*/ - // Subclasses should allocate vtPtr and then call WriteOverrides public VTable (CppTypeInfo typeInfo) { + this.initialized = false; this.typeInfo = typeInfo; + this.vtPtr = Marshal.AllocHGlobal ((EntryCount * EntrySize) + typeInfo.VTableTopPadding + typeInfo.VTableBottomPadding); + WriteOverrides (); } protected virtual void WriteOverrides () @@ -75,36 +77,54 @@ namespace Mono.VisualC.Interop.ABI { } } + public virtual T GetVirtualCallDelegate (CppInstancePtr instance, int index) + where T : class /*Delegate*/ + { + var vtable = instance.native_vtptr; + + var ftnptr = Marshal.ReadIntPtr (vtable, (index * EntrySize) + typeInfo.VTableTopPadding); + if (ftnptr == IntPtr.Zero) + throw new NullReferenceException ("Native VTable contains null...possible abstract class???"); + + var del = Marshal.GetDelegateForFunctionPointer (ftnptr, typeof (T)); + return del as T; + } + // FIXME: Make this method unsafe.. it would probably be much faster - public virtual void InitInstance (IntPtr instance) + public virtual void InitInstance (ref CppInstancePtr instance) { - if (basePtr == IntPtr.Zero) { - basePtr = Marshal.ReadIntPtr (instance); - if ((basePtr != IntPtr.Zero) && (basePtr != vtPtr)) { - // FIXME: This could probably be a more efficient memcpy - for(int i = 0; i < typeInfo.VTableTopPadding; i++) - Marshal.WriteByte(vtPtr, i, Marshal.ReadByte(basePtr, i)); - - int currentOffset = typeInfo.VTableTopPadding; - for (int i = 0; i < EntryCount; i++) { - if (Marshal.ReadIntPtr (vtPtr, currentOffset) == IntPtr.Zero) - Marshal.WriteIntPtr (vtPtr, currentOffset, Marshal.ReadIntPtr (basePtr, currentOffset)); - - currentOffset += EntrySize; - } - - // FIXME: This could probably be a more efficient memcpy - for(int i = 0; i < typeInfo.VTableBottomPadding; i++) - Marshal.WriteByte(vtPtr, currentOffset + i, Marshal.ReadByte(basePtr, currentOffset + i)); + var basePtr = Marshal.ReadIntPtr (instance.Native); + Debug.Assert (basePtr != IntPtr.Zero && basePtr != vtPtr); + + instance.native_vtptr = basePtr; + + if (!initialized) { + + // FIXME: This could probably be a more efficient memcpy + for (int i = 0; i < typeInfo.VTableTopPadding; i++) + Marshal.WriteByte(vtPtr, i, Marshal.ReadByte(basePtr, i)); + + int currentOffset = typeInfo.VTableTopPadding; + for (int i = 0; i < EntryCount; i++) { + if (Marshal.ReadIntPtr (vtPtr, currentOffset) == IntPtr.Zero) + Marshal.WriteIntPtr (vtPtr, currentOffset, Marshal.ReadIntPtr (basePtr, currentOffset)); + + currentOffset += EntrySize; } + + // FIXME: This could probably be a more efficient memcpy + for (int i = 0; i < typeInfo.VTableBottomPadding; i++) + Marshal.WriteByte(vtPtr, currentOffset + i, Marshal.ReadByte(basePtr, currentOffset + i)); + + initialized = true; } - Marshal.WriteIntPtr (instance, vtPtr); + Marshal.WriteIntPtr (instance.Native, vtPtr); } - public virtual void ResetInstance (IntPtr instance) + public virtual void ResetInstance (CppInstancePtr instance) { - Marshal.WriteIntPtr (instance, basePtr); + Marshal.WriteIntPtr (instance.Native, instance.native_vtptr); } public IntPtr Pointer { diff --git a/src/Mono.VisualC.Interop/ABI/VTableManaged.cs b/src/Mono.VisualC.Interop/ABI/VTableManaged.cs deleted file mode 100644 index a689e1db..00000000 --- a/src/Mono.VisualC.Interop/ABI/VTableManaged.cs +++ /dev/null @@ -1,73 +0,0 @@ -// -// Mono.VisualC.Interop.ABI.VTableManaged.cs: Managed vtable implementation -// -// Author: -// Alexander Corrado (alexander.corrado@gmail.com) -// Andreia Gaita (shana@spoiledcat.net) -// -// Copyright (C) 2010 Alexander Corrado -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; - -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.InteropServices; - -using Mono.VisualC.Interop.Util; - -namespace Mono.VisualC.Interop.ABI { - public class VTableManaged : VTable { - - public static MakeVTableDelegate Implementation = metadata => { return new VTableManaged (metadata); }; - private VTableManaged (CppTypeInfo metadata) : base (metadata) - { - this.vtPtr = Marshal.AllocHGlobal ((EntryCount * EntrySize) + typeInfo.VTableTopPadding + typeInfo.VTableBottomPadding); - WriteOverrides (); - } - - public override T GetVirtualCallDelegate (IntPtr native, int index) - { - IntPtr vtable = Marshal.ReadIntPtr (native); - if (vtable == vtPtr) // do not return managed overrides - vtable = basePtr; - - IntPtr ftnptr = Marshal.ReadIntPtr (vtable, (index * EntrySize) + typeInfo.VTableTopPadding); - if (ftnptr == IntPtr.Zero) - throw new NullReferenceException ("Native VTable contains null...possible abstract class???"); - - Delegate del = Marshal.GetDelegateForFunctionPointer (ftnptr, typeof (T)); - return del as T; - } - - } - - /* - protected static Type GetNativeLayoutType(MethodInfo thisMethod) { - ParameterInfo[] parameters = thisMethod.GetParameters(); - if (parameters.Length < 1) return null; - - Type nativeLayoutType = parameters[0].ParameterType.GetElementType(); - return nativeLayoutType; - } - */ -} diff --git a/src/Mono.VisualC.Interop/CppInstancePtr.cs b/src/Mono.VisualC.Interop/CppInstancePtr.cs index 83b40d9f..24cb5056 100644 --- a/src/Mono.VisualC.Interop/CppInstancePtr.cs +++ b/src/Mono.VisualC.Interop/CppInstancePtr.cs @@ -36,7 +36,9 @@ using Mono.VisualC.Interop.ABI; namespace Mono.VisualC.Interop { public struct CppInstancePtr : ICppObject { + private IntPtr ptr; + internal IntPtr native_vtptr; private bool manage_memory; private static Dictionary implCache = null; @@ -62,7 +64,7 @@ namespace Mono.VisualC.Interop { impl = (Iface)cachedImpl; CppInstancePtr instance = impl.Alloc (managed); - impl.TypeInfo.VTable.InitInstance ((IntPtr)instance); + impl.TypeInfo.VTable.InitInstance (ref instance); return instance; } @@ -76,6 +78,7 @@ namespace Mono.VisualC.Interop { ptr = Marshal.AllocHGlobal (allocSize); // zero memory for sanity + // FIXME: This should be an initblk byte[] zeroArray = new byte [allocSize]; Marshal.Copy (zeroArray, 0, ptr, allocSize); diff --git a/src/Mono.VisualC.Interop/CppTypeInfo.cs b/src/Mono.VisualC.Interop/CppTypeInfo.cs index 7f79f3b9..62ffbc17 100644 --- a/src/Mono.VisualC.Interop/CppTypeInfo.cs +++ b/src/Mono.VisualC.Interop/CppTypeInfo.cs @@ -216,9 +216,10 @@ namespace Mono.VisualC.Interop { } } - public virtual T GetAdjustedVirtualCall (IntPtr native, int derivedVirtualMethodIndex) where T : class /* Delegate */ + public virtual T GetAdjustedVirtualCall (CppInstancePtr instance, int derivedVirtualMethodIndex) + where T : class /* Delegate */ { - return VTable.GetVirtualCallDelegate (native, BaseVTableSlots + derivedVirtualMethodIndex); + return VTable.GetVirtualCallDelegate (instance, BaseVTableSlots + derivedVirtualMethodIndex); } public virtual VTable VTable { @@ -228,7 +229,7 @@ namespace Mono.VisualC.Interop { return null; if (lazy_vtable == null) - lazy_vtable = VTable.DefaultImplementation (this); + lazy_vtable = new VTable (this); return lazy_vtable; } diff --git a/src/Mono.VisualC.Interop/Makefile.am b/src/Mono.VisualC.Interop/Makefile.am index 4473b658..e0df2025 100644 --- a/src/Mono.VisualC.Interop/Makefile.am +++ b/src/Mono.VisualC.Interop/Makefile.am @@ -52,7 +52,6 @@ FILES = \ ABI/Impl/VirtualOnlyAbi.cs \ ABI/MethodType.cs \ ABI/VTable.cs \ - ABI/VTableManaged.cs \ AssemblyInfo.cs \ Attributes.cs \ CppField.cs \ diff --git a/src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj b/src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj index d29c3e54..a9e38fe4 100644 --- a/src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj +++ b/src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj @@ -61,7 +61,6 @@ - diff --git a/src/generator/Templates/CSharp/CSharpClass.cs b/src/generator/Templates/CSharp/CSharpClass.cs index 52156669..c0efbd86 100644 --- a/src/generator/Templates/CSharp/CSharpClass.cs +++ b/src/generator/Templates/CSharp/CSharpClass.cs @@ -19,7 +19,7 @@ namespace Templates { public partial class CSharpClass : Base { - #line 227 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 231 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" private void WriteMethodHeader (Method method, string initBases) { @@ -368,7 +368,10 @@ private bool IsByVal (CppType t) if (IsByVal (method.ReturnType)) { Write ("[return: ByVal] "); } - Write (GetCSharpType (method.ReturnType)); + if (method.IsConstructor) + Write ("CppInstancePtr"); + else + Write (GetCSharpType (method.ReturnType)); Write (" "); Write (method.Name); @@ -390,91 +393,91 @@ private bool IsByVal (CppType t) #line default #line hidden - #line 75 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 78 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\t}\n"); #line default #line hidden - #line 76 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 79 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" /* Native layout */ #line default #line hidden - #line 77 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 80 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\tprivate struct "); #line default #line hidden - #line 77 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 80 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( layout )); #line default #line hidden - #line 77 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 80 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" {\n"); #line default #line hidden - #line 78 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 81 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" foreach (var field in Class.Fields) { #line default #line hidden - #line 79 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 82 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\t\tpublic "); #line default #line hidden - #line 79 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 82 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( GetCSharpType (field.Type) )); #line default #line hidden - #line 79 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 82 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" "); #line default #line hidden - #line 79 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 82 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( field.Name )); #line default #line hidden - #line 79 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 82 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(";\n"); #line default #line hidden - #line 80 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 83 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" } #line default #line hidden - #line 81 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 84 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\t}\n\n"); #line default #line hidden - #line 83 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 86 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" /* Native fields */ #line default #line hidden - #line 84 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 87 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" PushIndent ("\t\t"); foreach (var field in Class.Fields.Where (f => f.Access != Access.@private)) { WriteLine ("{0} {1} {2} {{", field.Access, GetCSharpType (field.Type), field.Name); @@ -482,141 +485,142 @@ private bool IsByVal (CppType t) #line default #line hidden - #line 87 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 90 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\t\tget {\n\t\t\t\treturn impl."); #line default #line hidden - #line 88 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 91 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( field.Name )); #line default #line hidden - #line 88 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 91 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" [Native];\n\t\t\t}\n\t\t\tset {\n\t\t\t\timpl."); #line default #line hidden - #line 91 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 94 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( field.Name )); #line default #line hidden - #line 91 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 94 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" [Native] = value;\n\t\t\t}\n\t\t}\n"); #line default #line hidden - #line 94 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 97 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" } ClearIndent(); #line default #line hidden - #line 96 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 99 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\n"); #line default #line hidden - #line 97 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 100 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" /* Native constructor */ #line default #line hidden - #line 98 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 101 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\tpublic "); #line default #line hidden - #line 98 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 101 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); #line default #line hidden - #line 98 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 101 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" (CppInstancePtr native)\n\t\t"); #line default #line hidden - #line 99 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 102 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( initBases )); #line default #line hidden - #line 99 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 102 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\n\t\t\tNative = native;\n\t\t}\n\n"); #line default #line hidden - #line 103 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 106 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" /* Subclass constructor */ #line default #line hidden - #line 104 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 107 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\tpublic "); #line default #line hidden - #line 104 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 107 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); #line default #line hidden - #line 104 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 107 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" (CppTypeInfo subClass)\n\t\t"); #line default #line hidden - #line 105 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 108 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( initBases )); #line default #line hidden - #line 105 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 108 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\n\t\t\tsubClass.AddBase (impl.TypeInfo);\n\t\t}\n\n"); #line default #line hidden - #line 109 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 112 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" /* Wrapper methods */ #line default #line hidden - #line 110 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 113 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" PushIndent ("\t\t"); foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) { WriteMethodHeader (method, initBases); - if (method.IsConstructor) { - Write ("Native = impl.Alloc (this);\n"); - Write (CurrentIndent); - } + if (method.IsConstructor) + Write ("Native = "); Write ("impl.{0} (", method.Name); if (!method.IsStatic) { - Write ("Native"); + if (method.IsConstructor) + Write ("impl.Alloc (this)"); + else + Write ("Native"); if (method.Parameters.Count != 0) Write (", "); } @@ -630,19 +634,19 @@ private bool IsByVal (CppType t) #line default #line hidden - #line 132 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 136 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\n"); #line default #line hidden - #line 133 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 137 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" /* Wrapper properties */ #line default #line hidden - #line 134 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 138 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" PushIndent ("\t\t"); foreach (var prop in Class.Properties) { var type = GetCSharpType (prop.Type); @@ -690,13 +694,13 @@ private bool IsByVal (CppType t) #line default #line hidden - #line 177 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 181 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\n"); #line default #line hidden - #line 178 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 182 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" /* Make this wrapper castable to non-primary bases */ foreach (var npBase in Class.BaseClasses.Skip (1)) { var prop = npBase.Name; @@ -706,157 +710,157 @@ foreach (var npBase in Class.BaseClasses.Skip (1)) { #line default #line hidden - #line 183 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 187 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\t// Non-primary base class implementation for "); #line default #line hidden - #line 183 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 187 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 183 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 187 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(":\n\t\tprivate "); #line default #line hidden - #line 184 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 188 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 184 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 188 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" "); #line default #line hidden - #line 184 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 188 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( field )); #line default #line hidden - #line 184 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 188 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(";\n\t\tpublic "); #line default #line hidden - #line 185 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 189 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 185 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 189 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" "); #line default #line hidden - #line 185 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 189 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( prop )); #line default #line hidden - #line 185 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 189 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" {\n\t\t\tget {\n\t\t\t\tif ("); #line default #line hidden - #line 187 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 191 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( field )); #line default #line hidden - #line 187 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 191 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" == null)\n\t\t\t\t\t"); #line default #line hidden - #line 188 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 192 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( field )); #line default #line hidden - #line 188 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 192 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" = impl.TypeInfo.Cast<"); #line default #line hidden - #line 188 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 192 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 188 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 192 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("> (this);\n\t\t\t\treturn "); #line default #line hidden - #line 189 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 193 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( field )); #line default #line hidden - #line 189 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 193 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(";\n\t\t\t}\n\t\t}\n\t\tpublic static implicit operator "); #line default #line hidden - #line 192 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 196 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 192 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 196 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("("); #line default #line hidden - #line 192 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 196 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); #line default #line hidden - #line 192 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 196 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" subClass)\n\t\t{\n\t\t\treturn subClass."); #line default #line hidden - #line 194 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 198 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( prop )); #line default #line hidden - #line 194 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 198 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(";\n\t\t}\n\n"); #line default #line hidden - #line 197 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 201 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" PushIndent ("\t\t"); foreach (var method in npBase.Methods) { // With the exception of virtual methods that have been overridden, these methods must be called @@ -879,43 +883,43 @@ foreach (var npBase in Class.BaseClasses.Skip (1)) { #line default #line hidden - #line 215 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 219 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\n\t\tpublic "); #line default #line hidden - #line 216 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 220 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( hasBase? "override" : "virtual" )); #line default #line hidden - #line 216 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 220 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" void Dispose ()\n\t\t{\n"); #line default #line hidden - #line 218 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 222 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" if (Class.Methods.Any (m => m.IsDestructor && !m.IsArtificial)) { #line default #line hidden - #line 219 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 223 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\t\timpl.Destruct (Native);\n"); #line default #line hidden - #line 220 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 224 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" } #line default #line hidden - #line 221 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 225 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\t\tNative.Dispose ();\n\t\t}\n\n\t}\n}\n\n"); #line default diff --git a/src/generator/Templates/CSharp/CSharpClass.tt b/src/generator/Templates/CSharp/CSharpClass.tt index 76b8687a..0da16193 100644 --- a/src/generator/Templates/CSharp/CSharpClass.tt +++ b/src/generator/Templates/CSharp/CSharpClass.tt @@ -54,7 +54,10 @@ namespace <#= Generator.Namespace #> { if (IsByVal (method.ReturnType)) { Write ("[return: ByVal] "); } - Write (GetCSharpType (method.ReturnType)); + if (method.IsConstructor) + Write ("CppInstancePtr"); + else + Write (GetCSharpType (method.ReturnType)); Write (" "); Write (method.Name); @@ -112,14 +115,15 @@ namespace <#= Generator.Namespace #> { WriteMethodHeader (method, initBases); - if (method.IsConstructor) { - Write ("Native = impl.Alloc (this);\n"); - Write (CurrentIndent); - } + if (method.IsConstructor) + Write ("Native = "); Write ("impl.{0} (", method.Name); if (!method.IsStatic) { - Write ("Native"); + if (method.IsConstructor) + Write ("impl.Alloc (this)"); + else + Write ("Native"); if (method.Parameters.Count != 0) Write (", "); } diff --git a/tests/Native/VirtualTests.cpp b/tests/Native/VirtualTests.cpp index aeb536e6..95cdf8d9 100644 --- a/tests/Native/VirtualTests.cpp +++ b/tests/Native/VirtualTests.cpp @@ -68,4 +68,17 @@ int ClassThatOverridesStuff::Number () const int ClassThatOverridesStuff::BaseNumber () const { return this->NumberClass::Number (); +} +NumberClass* ClassThatOverridesStuff::GetInstance (int num, int my) +{ + return new ClassThatOverridesStuff (num, my); +} + +ClassThatRoundtrips::ClassThatRoundtrips (NumberClass* managed) +{ + this->nc = managed; +} +NumberClass* ClassThatRoundtrips::GetIt () +{ + return this->nc; } \ No newline at end of file diff --git a/tests/Native/VirtualTests.h b/tests/Native/VirtualTests.h index 7ffc25fc..c244d731 100644 --- a/tests/Native/VirtualTests.h +++ b/tests/Native/VirtualTests.h @@ -51,4 +51,13 @@ public: ClassThatOverridesStuff (int num, int my); virtual int Number () const; virtual int BaseNumber () const; + static NumberClass* GetInstance (int num, int my); +}; + +class ClassThatRoundtrips { +protected: + NumberClass* nc; +public: + ClassThatRoundtrips (NumberClass* managed); + virtual NumberClass* GetIt (); }; \ No newline at end of file diff --git a/tests/VirtualTests.cs b/tests/VirtualTests.cs index 7200a1e5..2672b5ca 100644 --- a/tests/VirtualTests.cs +++ b/tests/VirtualTests.cs @@ -67,7 +67,7 @@ namespace Tests { } [Test] - public void TestClassThatOverridesStuff () + public void TestNativeOverride1 () { var cls = new ClassThatOverridesStuff (5, 3); Assert.AreEqual (3, cls.Number, "#1"); @@ -76,6 +76,16 @@ namespace Tests { Assert.AreEqual (5, cls.BaseNumber, "#4"); } + [Test] + public void TestNativeOverride2 () + { + var cls = ClassThatOverridesStuff.GetInstance (5, 3); + Assert.AreEqual (3, cls.Number, "#1"); + Assert.AreEqual (3, ((NumberClass)cls).Number, "#2"); + Assert.AreEqual (-3, cls.NegativeNumber, "#3"); + Assert.AreEqual (5, ((ClassThatOverridesStuff)cls).BaseNumber, "#4"); + } + class ManagedOverride1 : NumberClass { public ManagedOverride1 () : base (3) @@ -105,7 +115,7 @@ namespace Tests { // override virtual member inherited from non-primary base public override void Multiply (int n) { - this.MultiplierClass.Multiply (10); + base.Multiply (10); } } @@ -113,7 +123,7 @@ namespace Tests { public void TestManagedOverride2 () { var cls = new ManagedOverride2 (); - cls.Multiply (3); + cls.Multiply (7); Assert.AreEqual (5, cls.Number, "#1"); Assert.AreEqual (30, ((MultiplierClass)cls).Number, "#2"); cls.CallMultiply (2); @@ -121,6 +131,15 @@ namespace Tests { Assert.AreEqual (300, ((MultiplierClass)cls).Number, "#4"); } + [Test] + public void TestRoundtripManagedOverride () + { + var managed = new ManagedOverride1 (); + var roundtripper = new ClassThatRoundtrips (managed); + var cls = roundtripper.GetIt (); + Assert.AreEqual (25, cls.Number, "#1"); + Assert.AreEqual (-25, cls.NegativeNumber, "#2"); + } } }