Browse Source

Begin hacking on per-instance vtptr. More failing tests.

pull/1/head
Alex Corrado 14 years ago
parent
commit
0febce15f3
  1. 59
      src/Mono.VisualC.Interop/ABI/CppAbi.cs
  2. 52
      src/Mono.VisualC.Interop/ABI/VTable.cs
  3. 73
      src/Mono.VisualC.Interop/ABI/VTableManaged.cs
  4. 5
      src/Mono.VisualC.Interop/CppInstancePtr.cs
  5. 7
      src/Mono.VisualC.Interop/CppTypeInfo.cs
  6. 1
      src/Mono.VisualC.Interop/Makefile.am
  7. 1
      src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj
  8. 162
      src/generator/Templates/CSharp/CSharpClass.cs
  9. 12
      src/generator/Templates/CSharp/CSharpClass.tt
  10. 13
      tests/Native/VirtualTests.cpp
  11. 9
      tests/Native/VirtualTests.h
  12. 25
      tests/VirtualTests.cs

59
src/Mono.VisualC.Interop/ABI/CppAbi.cs

@ -225,7 +225,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -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 { @@ -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 { @@ -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 { @@ -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<T> (native, vtableIndex);
// this._typeInfo.GetAdjustedVirtualCall<T> (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 { @@ -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 { @@ -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 ();
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);
EmitCheckManagedAlloc (il, cppInstancePtr);
EmitResetVTable (il, nativePtr);
EmitResetVTable (il, cppInstancePtr);
EmitNativeCall (il, nativeMethod, psig, nativePtr);
il.MarkLabel (bail);
}
/**
@ -538,12 +538,14 @@ namespace Mono.VisualC.Interop.ABI { @@ -538,12 +538,14 @@ namespace Mono.VisualC.Interop.ABI {
il.Emit (OpCodes.Call, nativeMethod);
// Marshal return value
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<Type> (parameters.Length);
@ -554,10 +556,11 @@ namespace Mono.VisualC.Interop.ABI { @@ -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 { @@ -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 { @@ -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);

52
src/Mono.VisualC.Interop/ABI/VTable.cs

@ -27,6 +27,7 @@ @@ -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; @@ -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 { @@ -50,12 +51,13 @@ namespace Mono.VisualC.Interop.ABI {
get { return Marshal.SizeOf (typeof (IntPtr)); }
}
public abstract T GetVirtualCallDelegate<T> (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,14 +77,31 @@ namespace Mono.VisualC.Interop.ABI { @@ -75,14 +77,31 @@ namespace Mono.VisualC.Interop.ABI {
}
}
public virtual T GetVirtualCallDelegate<T> (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)) {
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++)
for (int i = 0; i < typeInfo.VTableTopPadding; i++)
Marshal.WriteByte(vtPtr, i, Marshal.ReadByte(basePtr, i));
int currentOffset = typeInfo.VTableTopPadding;
@ -94,17 +113,18 @@ namespace Mono.VisualC.Interop.ABI { @@ -94,17 +113,18 @@ namespace Mono.VisualC.Interop.ABI {
}
// FIXME: This could probably be a more efficient memcpy
for(int i = 0; i < typeInfo.VTableBottomPadding; i++)
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 {

73
src/Mono.VisualC.Interop/ABI/VTableManaged.cs

@ -1,73 +0,0 @@ @@ -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<T> (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;
}
*/
}

5
src/Mono.VisualC.Interop/CppInstancePtr.cs

@ -36,7 +36,9 @@ using Mono.VisualC.Interop.ABI; @@ -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<Type,object> implCache = null;
@ -62,7 +64,7 @@ namespace Mono.VisualC.Interop { @@ -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 { @@ -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);

7
src/Mono.VisualC.Interop/CppTypeInfo.cs

@ -216,9 +216,10 @@ namespace Mono.VisualC.Interop { @@ -216,9 +216,10 @@ namespace Mono.VisualC.Interop {
}
}
public virtual T GetAdjustedVirtualCall<T> (IntPtr native, int derivedVirtualMethodIndex) where T : class /* Delegate */
public virtual T GetAdjustedVirtualCall<T> (CppInstancePtr instance, int derivedVirtualMethodIndex)
where T : class /* Delegate */
{
return VTable.GetVirtualCallDelegate<T> (native, BaseVTableSlots + derivedVirtualMethodIndex);
return VTable.GetVirtualCallDelegate<T> (instance, BaseVTableSlots + derivedVirtualMethodIndex);
}
public virtual VTable VTable {
@ -228,7 +229,7 @@ namespace Mono.VisualC.Interop { @@ -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;
}

1
src/Mono.VisualC.Interop/Makefile.am

@ -52,7 +52,6 @@ FILES = \ @@ -52,7 +52,6 @@ FILES = \
ABI/Impl/VirtualOnlyAbi.cs \
ABI/MethodType.cs \
ABI/VTable.cs \
ABI/VTableManaged.cs \
AssemblyInfo.cs \
Attributes.cs \
CppField.cs \

1
src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj

@ -61,7 +61,6 @@ @@ -61,7 +61,6 @@
<Compile Include="AssemblyInfo.cs" />
<Compile Include="ABI\CppAbi.cs" />
<Compile Include="Interfaces.cs" />
<Compile Include="ABI\VTableManaged.cs" />
<Compile Include="Attributes.cs" />
<Compile Include="CppInstancePtr.cs" />
<Compile Include="CppField.cs" />

162
src/generator/Templates/CSharp/CSharpClass.cs

@ -19,7 +19,7 @@ namespace Templates { @@ -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,6 +368,9 @@ private bool IsByVal (CppType t) @@ -368,6 +368,9 @@ private bool IsByVal (CppType t)
if (IsByVal (method.ReturnType)) {
Write ("[return: ByVal] ");
}
if (method.IsConstructor)
Write ("CppInstancePtr");
else
Write (GetCSharpType (method.ReturnType));
Write (" ");
Write (method.Name);
@ -390,91 +393,91 @@ private bool IsByVal (CppType t) @@ -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,140 +485,141 @@ private bool IsByVal (CppType t) @@ -482,140 +485,141 @@ 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) {
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) @@ -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) @@ -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)) { @@ -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)) { @@ -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

12
src/generator/Templates/CSharp/CSharpClass.tt

@ -54,6 +54,9 @@ namespace <#= Generator.Namespace #> { @@ -54,6 +54,9 @@ namespace <#= Generator.Namespace #> {
if (IsByVal (method.ReturnType)) {
Write ("[return: ByVal] ");
}
if (method.IsConstructor)
Write ("CppInstancePtr");
else
Write (GetCSharpType (method.ReturnType));
Write (" ");
Write (method.Name);
@ -112,13 +115,14 @@ namespace <#= Generator.Namespace #> { @@ -112,13 +115,14 @@ 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) {
if (method.IsConstructor)
Write ("impl.Alloc (this)");
else
Write ("Native");
if (method.Parameters.Count != 0)
Write (", ");

13
tests/Native/VirtualTests.cpp

@ -69,3 +69,16 @@ int ClassThatOverridesStuff::BaseNumber () const @@ -69,3 +69,16 @@ 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;
}

9
tests/Native/VirtualTests.h

@ -51,4 +51,13 @@ public: @@ -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 ();
};

25
tests/VirtualTests.cs

@ -67,7 +67,7 @@ namespace Tests { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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");
}
}
}

Loading…
Cancel
Save