Skip to content

Commit 6609e03

Browse files
committed
[Java.Base-Tests] Test Java-to-Managed invocations for Java.Base
Commit bc5bcf4 (Desktop `Java.Base` binding) had a TODO: > ~~ TODO: Marshal Methods ~~ > > Marshal methods are currently skipped. Java-to-managed invocations > are not currently supported. No marshal methods means no facility for Java-to-managed invocations. Add a new `tests/Java.Base-Tests` unit test assembly, and test Java-to-managed invocations. This requires touching and updating ~everything. 😅 Update `Java.Interop.dll` to contain a new `Java.Interop.JniMethodSignatureAttribute` custom attribute. Update `generator` to begin emitting `[JniMethodSignature]` on bound methods. This is necessary so that `jcw-gen` knows the JNI method signature of Java methods to emit. As part of this, *remove* the `JniTypeSignatureAttr` type added in bc5bcf4; trying to follow the `JniTypeSignatureAttr` pattern for `JniMethodSignatureAttr` would make for more intrusive code changes. Instead, "re-use" the existing `RegisterAttr` type, adding a `RegisterAttr.MemberType` property so that we can select between Android `[Register]` output vs. "Desktop" `[JniTypeSignature]` and `[JniMethodSignature]` output. Update `Java.Interop.Tools.JavaCallableWrappers` to look for `Java.Interop.JniTypeSignatureAttribute` and `Java.Interop.JniMethodSignatureAttribute`. This allows `jcw-gen Java.Base-Tests.dll` to generate Java Callable Wrappers for `Java.BaseTests.MyRunnable`. Update `Java.Interop.Export.dll` so that `MarshalMemberBuilder` doesn't use `Expression.GetActionType()` or `Expression.GetFuncType()`, as .NET doesn't support the use of generic types in [`Marshal.GetFunctionPointerForDelegate()`][0]. Instead, we need to use `System.Reflection.Emit` to define our own custom delegate types. [0]: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.getfunctionpointerfordelegate?view=net-6.0
1 parent 2a882d2 commit 6609e03

35 files changed

+2318
-161
lines changed

Directory.Build.targets

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<!-- NuGet Dependencies -->
1313
<ItemGroup>
14+
<PackageReference Update="coverlet.collector" Version="3.1.0" />
1415
<PackageReference Update="Microsoft.Xml.SgmlReader" Version="1.8.16" />
1516
<PackageReference Update="GitInfo" Version="2.1.2" />
1617
<PackageReference Update="HtmlAgilityPack" Version="1.11.30" />
@@ -33,6 +34,8 @@
3334
</PackageReference>
3435
<PackageReference Update="protobuf-net" Version="2.4.4" />
3536
<PackageReference Update="XliffTasks" Version="1.0.0-beta.20420.1" />
37+
<PackageReference Update="xunit" Version="2.4.1" />
38+
<PackageReference Update="xunit.runner.visualstudio" Version="2.4.1" />
3639
</ItemGroup>
3740

3841
<Import Project="build-tools\scripts\VersionInfo.targets" />

Java.Interop.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.JavaType
105105
EndProject
106106
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Base", "src\Java.Base\Java.Base.csproj", "{30DCECA5-16FD-4FD0-883C-E5E83B11565D}"
107107
EndProject
108+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Base-Tests", "tests\Java.Base-Tests\Java.Base-Tests.csproj", "{CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}"
109+
EndProject
108110
Global
109111
GlobalSection(SharedMSBuildProjectFiles) = preSolution
110112
src\Java.Interop.NamingCustomAttributes\Java.Interop.NamingCustomAttributes.projitems*{58b564a1-570d-4da2-b02d-25bddb1a9f4f}*SharedItemsImports = 5
@@ -296,6 +298,10 @@ Global
296298
{30DCECA5-16FD-4FD0-883C-E5E83B11565D}.Debug|Any CPU.Build.0 = Debug|Any CPU
297299
{30DCECA5-16FD-4FD0-883C-E5E83B11565D}.Release|Any CPU.ActiveCfg = Release|Any CPU
298300
{30DCECA5-16FD-4FD0-883C-E5E83B11565D}.Release|Any CPU.Build.0 = Release|Any CPU
301+
{CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
302+
{CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
303+
{CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
304+
{CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}.Release|Any CPU.Build.0 = Release|Any CPU
299305
EndGlobalSection
300306
GlobalSection(SolutionProperties) = preSolution
301307
HideSolutionNode = FALSE
@@ -346,6 +352,7 @@ Global
346352
{B173F53B-986C-4E0D-881C-063BBB116E1D} = {0998E45F-8BCE-4791-A944-962CD54E2D80}
347353
{11942DE9-AEC2-4B95-87AB-CA707C37643D} = {271C9F30-F679-4793-942B-0D9527CB3E2F}
348354
{30DCECA5-16FD-4FD0-883C-E5E83B11565D} = {0998E45F-8BCE-4791-A944-962CD54E2D80}
355+
{CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC} = {271C9F30-F679-4793-942B-0D9527CB3E2F}
349356
EndGlobalSection
350357
GlobalSection(ExtensibilityGlobals) = postSolution
351358
SolutionGuid = {29204E0C-382A-49A0-A814-AD7FBF9774A5}

src/Java.Base-ref.cs

Lines changed: 1664 additions & 31 deletions
Large diffs are not rendered by default.

src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Linq.Expressions;
66
using System.Reflection;
7+
using System.Reflection.Emit;
78
using System.Text;
89

910
using Java.Interop.Expressions;
@@ -241,15 +242,6 @@ public LambdaExpression CreateMarshalToManagedExpression (MethodInfo method, Jav
241242

242243
static Type GetMarshalerType (Type returnType, List<Type> funcTypeParams, Type declaringType)
243244
{
244-
// `mscorlib.dll` & `System.Core.dll` only provide Action<…>/Func<…> types for up to 16 parameters
245-
if (funcTypeParams.Count <= 16) {
246-
if (returnType != null)
247-
funcTypeParams.Add (returnType);
248-
return returnType == null
249-
? Expression.GetActionType (funcTypeParams.ToArray ())
250-
: Expression.GetFuncType (funcTypeParams.ToArray ());
251-
}
252-
253245
// Too many parameters; does a `_JniMarshal_*` type exist in the type's declaring assembly?
254246
funcTypeParams.RemoveRange (0, 2);
255247
var marshalDelegateName = new StringBuilder ();
@@ -265,11 +257,58 @@ static Type GetMarshalerType (Type returnType, List<Type> funcTypeParams, Type d
265257
}
266258

267259
Type marshalDelegateType = declaringType.Assembly.GetType (marshalDelegateName.ToString (), throwOnError: false);
260+
if (marshalDelegateType != null) {
261+
return marshalDelegateType;
262+
}
268263

264+
#if !NET
269265
// Punt?; System.Linq.Expressions will automagically produce the needed delegate type.
270266
// Unfortunately, this won't work with jnimarshalmethod-gen.exe.
271267
return marshalDelegateType;
268+
#else // NET
269+
return CreateMarshalDelegateType (marshalDelegateName.ToString (), returnType, funcTypeParams);
270+
#endif // NET
271+
}
272+
273+
#if NET
274+
static object ab_lock = new object ();
275+
static AssemblyBuilder assemblyBuilder;
276+
static ModuleBuilder moduleBuilder;
277+
static Type[] DelegateCtorSignature;
278+
279+
static Type CreateMarshalDelegateType (string name, Type returnType, List<Type> funcTypeParams)
280+
{
281+
lock (ab_lock) {
282+
if (assemblyBuilder == null) {
283+
var aname = new AssemblyName ("jni-marshal-method-delegates");
284+
assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);
285+
moduleBuilder = assemblyBuilder.DefineDynamicModule (aname.Name!);
286+
287+
DelegateCtorSignature = new Type[] {
288+
typeof (object),
289+
typeof (IntPtr)
290+
};
291+
}
292+
funcTypeParams.Insert (0, typeof (IntPtr));
293+
funcTypeParams.Insert (0, typeof (IntPtr));
294+
var typeBuilder = moduleBuilder.DefineType (
295+
name,
296+
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass,
297+
typeof (MulticastDelegate)
298+
);
299+
300+
const MethodAttributes CtorAttributes = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
301+
const MethodImplAttributes ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed;
302+
const MethodAttributes InvokeAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
303+
304+
typeBuilder.DefineConstructor (CtorAttributes, CallingConventions.Standard, DelegateCtorSignature)
305+
.SetImplementationFlags (ImplAttributes);
306+
typeBuilder.DefineMethod ("Invoke", InvokeAttributes, returnType, funcTypeParams.ToArray ())
307+
.SetImplementationFlags (ImplAttributes);
308+
return typeBuilder.CreateTypeInfo ();
309+
}
272310
}
311+
#endif // NET
273312

274313
static char GetJniMarshalDelegateParameterIdentifier (Type type)
275314
{

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs

Lines changed: 106 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020

2121
namespace Java.Interop.Tools.JavaCallableWrappers {
2222

23+
public enum JavaPeerStyle {
24+
XAJavaInterop1,
25+
JavaInterop1,
26+
}
27+
2328
public class JavaCallableWrapperGenerator {
2429

2530
class JavaFieldInfo {
@@ -76,6 +81,7 @@ public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[
7681
}
7782

7883
public string ApplicationJavaClass { get; set; }
84+
public JavaPeerStyle CodeGenerationTarget { get; set; }
7985

8086
public bool GenerateOnCreateOverrides { get; set; }
8187

@@ -101,7 +107,7 @@ void AddNestedTypes (TypeDefinition type)
101107
continue;
102108
if (!JavaNativeTypeManager.IsNonStaticInnerClass (nt, cache))
103109
continue;
104-
children.Add (new JavaCallableWrapperGenerator (nt, JavaNativeTypeManager.ToJniName (type), log, cache));
110+
children.Add (new JavaCallableWrapperGenerator (nt, JavaNativeTypeManager.ToJniName (type, cache), log, cache));
105111
if (nt.HasNestedTypes)
106112
AddNestedTypes (nt);
107113
}
@@ -117,7 +123,7 @@ void AddNestedTypes (TypeDefinition type)
117123
if (type.IsEnum || type.IsInterface || type.IsValueType)
118124
Diagnostic.Error (4200, LookupSource (type), Localization.Resources.JavaCallableWrappers_XA4200, type.FullName);
119125

120-
string jniName = JavaNativeTypeManager.ToJniName (type);
126+
string jniName = JavaNativeTypeManager.ToJniName (type, resolver);
121127
if (jniName == null)
122128
Diagnostic.Error (4201, LookupSource (type), Localization.Resources.JavaCallableWrappers_XA4201, type.FullName);
123129
if (!string.IsNullOrEmpty (outerType)) {
@@ -157,7 +163,7 @@ void AddNestedTypes (TypeDefinition type)
157163
r.FullName);
158164
return d;
159165
})
160-
.Where (d => GetRegisterAttributes (d).Any ())
166+
.Where (d => GetTypeRegistrationAttributes (d).Any ())
161167
.SelectMany (d => d.Methods)
162168
.Where (m => !m.IsStatic)) {
163169
AddMethod (imethod, imethod);
@@ -168,7 +174,7 @@ void AddNestedTypes (TypeDefinition type)
168174
};
169175
foreach (var bt in type.GetBaseTypes (cache)) {
170176
ctorTypes.Add (bt);
171-
RegisterAttribute rattr = GetRegisterAttributes (bt).FirstOrDefault ();
177+
RegisterAttribute rattr = GetMethodRegistrationAttributes (bt).FirstOrDefault ();
172178
if (rattr != null && rattr.DoNotGenerateAcw)
173179
break;
174180
}
@@ -271,7 +277,7 @@ void AddConstructor (MethodDefinition ctor, TypeDefinition type, string outerTyp
271277
return;
272278
}
273279

274-
RegisterAttribute rattr = GetRegisterAttributes (ctor).FirstOrDefault ();
280+
RegisterAttribute rattr = GetMethodRegistrationAttributes (ctor).FirstOrDefault ();
275281
if (rattr != null) {
276282
if (ctors.Any (c => c.JniSignature == rattr.Signature))
277283
return;
@@ -335,6 +341,34 @@ internal static RegisterAttribute ToRegisterAttribute (CustomAttribute attr)
335341
return r;
336342
}
337343

344+
internal static RegisterAttribute RegisterFromJniTypeSignatureAttribute (CustomAttribute attr)
345+
{
346+
// attr.Resolve ();
347+
RegisterAttribute r = null;
348+
if (attr.ConstructorArguments.Count == 1)
349+
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value);
350+
if (r != null) {
351+
var v = attr.Properties.FirstOrDefault (p => p.Name == "GenerateJavaPeer");
352+
if (v.Name == null) {
353+
r.DoNotGenerateAcw = false;
354+
} else if (v.Name == "GenerateJavaPeer") {
355+
r.DoNotGenerateAcw = ! (bool) v.Argument.Value;
356+
}
357+
}
358+
return r;
359+
}
360+
361+
internal static RegisterAttribute RegisterFromJniMethodSignatureAttribute (CustomAttribute attr)
362+
{
363+
// attr.Resolve ();
364+
RegisterAttribute r = null;
365+
if (attr.ConstructorArguments.Count == 2)
366+
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value,
367+
(string) attr.ConstructorArguments [1].Value,
368+
"");
369+
return r;
370+
}
371+
338372
ExportAttribute ToExportAttribute (CustomAttribute attr, IMemberDefinition declaringMember)
339373
{
340374
var name = attr.ConstructorArguments.Count > 0 ? (string) attr.ConstructorArguments [0].Value : declaringMember.Name;
@@ -351,9 +385,24 @@ internal static ExportFieldAttribute ToExportFieldAttribute (CustomAttribute att
351385
return new ExportFieldAttribute ((string) attr.ConstructorArguments [0].Value);
352386
}
353387

354-
static IEnumerable<RegisterAttribute> GetRegisterAttributes (Mono.Cecil.ICustomAttributeProvider p)
388+
internal static IEnumerable<RegisterAttribute> GetTypeRegistrationAttributes (Mono.Cecil.ICustomAttributeProvider p)
355389
{
356-
return GetAttributes<RegisterAttribute> (p, a => ToRegisterAttribute (a));
390+
foreach (var a in GetAttributes<RegisterAttribute> (p, a => ToRegisterAttribute (a))) {
391+
yield return a;
392+
}
393+
foreach (var c in p.GetCustomAttributes ("Java.Interop.JniTypeSignatureAttribute")) {
394+
yield return RegisterFromJniTypeSignatureAttribute (c);
395+
}
396+
}
397+
398+
static IEnumerable<RegisterAttribute> GetMethodRegistrationAttributes (Mono.Cecil.ICustomAttributeProvider p)
399+
{
400+
foreach (var a in GetAttributes<RegisterAttribute> (p, a => ToRegisterAttribute (a))) {
401+
yield return a;
402+
}
403+
foreach (var c in p.GetCustomAttributes ("Java.Interop.JniMethodSignatureAttribute")) {
404+
yield return RegisterFromJniMethodSignatureAttribute (c);
405+
}
357406
}
358407

359408
IEnumerable<ExportAttribute> GetExportAttributes (IMemberDefinition p)
@@ -375,7 +424,7 @@ static IEnumerable<TAttribute> GetAttributes<TAttribute> (Mono.Cecil.ICustomAttr
375424
void AddMethod (MethodDefinition registeredMethod, MethodDefinition implementedMethod)
376425
{
377426
if (registeredMethod != null)
378-
foreach (RegisterAttribute attr in GetRegisterAttributes (registeredMethod)) {
427+
foreach (RegisterAttribute attr in GetMethodRegistrationAttributes (registeredMethod)) {
379428
// Check for Kotlin-mangled methods that cannot be overridden
380429
if (attr.Name.Contains ("-impl") || (attr.Name.Length > 7 && attr.Name[attr.Name.Length - 8] == '-'))
381430
Diagnostic.Error (4217, LookupSource (implementedMethod), Localization.Resources.JavaCallableWrappers_XA4217, attr.Name);
@@ -544,19 +593,27 @@ void GenerateHeader (TextWriter sw)
544593

545594
sw.WriteLine ("public " + (type.IsAbstract ? "abstract " : "") + "class " + name);
546595

547-
string extendsType = GetJavaTypeName (type.BaseType);
596+
string extendsType = GetJavaTypeName (type.BaseType, cache);
548597
if (extendsType == "android.app.Application" && !string.IsNullOrEmpty (ApplicationJavaClass))
549598
extendsType = ApplicationJavaClass;
550599
sw.WriteLine ("\textends " + extendsType);
551600
sw.WriteLine ("\timplements");
552-
sw.Write ("\t\tmono.android.IGCUserPeer");
601+
sw.Write ("\t\t");
602+
switch (CodeGenerationTarget) {
603+
case JavaPeerStyle.JavaInterop1:
604+
sw.Write ("com.xamarin.java_interop.GCUserPeerable");
605+
break;
606+
default:
607+
sw.Write ("mono.android.IGCUserPeer");
608+
break;
609+
}
553610
IEnumerable<TypeDefinition> ifaces = type.Interfaces.Select (ifaceInfo => ifaceInfo.InterfaceType)
554611
.Select (r => r.Resolve ())
555-
.Where (d => GetRegisterAttributes (d).Any ());
612+
.Where (d => GetTypeRegistrationAttributes (d).Any ());
556613
if (ifaces.Any ()) {
557614
foreach (TypeDefinition iface in ifaces) {
558615
sw.WriteLine (",");
559-
sw.Write ("\t\t{0}", GetJavaTypeName (iface));
616+
sw.Write ("\t\t{0}", GetJavaTypeName (iface, cache));
560617
}
561618
}
562619
sw.WriteLine ();
@@ -590,16 +647,23 @@ void GenerateBody (TextWriter sw)
590647
w.WriteLine ("\t\tsuper.onCreate (arguments);");
591648
});
592649

650+
string addRef = "monodroidAddReference";
651+
string clearRefs = "monodroidClearReferences";
652+
if (CodeGenerationTarget == JavaPeerStyle.JavaInterop1) {
653+
addRef = "jiAddManagedReference";
654+
clearRefs = "jiClearManagedReferences";
655+
}
656+
593657
sw.WriteLine ();
594658
sw.WriteLine ("\tprivate java.util.ArrayList refList;");
595-
sw.WriteLine ("\tpublic void monodroidAddReference (java.lang.Object obj)");
659+
sw.WriteLine ($"\tpublic void {addRef} (java.lang.Object obj)");
596660
sw.WriteLine ("\t{");
597661
sw.WriteLine ("\t\tif (refList == null)");
598662
sw.WriteLine ("\t\t\trefList = new java.util.ArrayList ();");
599663
sw.WriteLine ("\t\trefList.add (obj);");
600664
sw.WriteLine ("\t}");
601665
sw.WriteLine ();
602-
sw.WriteLine ("\tpublic void monodroidClearReferences ()");
666+
sw.WriteLine ($"\tpublic void {clearRefs} ()");
603667
sw.WriteLine ("\t{");
604668
sw.WriteLine ("\t\tif (refList != null)");
605669
sw.WriteLine ("\t\t\trefList.clear ();");
@@ -612,9 +676,19 @@ void GenerateRegisterType (TextWriter sw, JavaCallableWrapperGenerator self, str
612676
foreach (Signature method in self.methods)
613677
sw.WriteLine ("\t\t\t\"{0}\\n\" +", method.Method);
614678
sw.WriteLine ("\t\t\t\"\";");
615-
if (!CannotRegisterInStaticConstructor (self.type))
616-
sw.WriteLine ("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {2});",
617-
self.type.GetPartialAssemblyQualifiedName (cache), self.name, field);
679+
if (CannotRegisterInStaticConstructor (self.type))
680+
return;
681+
string format = null;
682+
switch (CodeGenerationTarget) {
683+
case JavaPeerStyle.JavaInterop1:
684+
format = "com.xamarin.java_interop.ManagedPeer.registerNativeMembers ({1}.class, \"{0}\", {2});";
685+
break;
686+
default:
687+
format = "mono.android.Runtime.register (\"{0}\", {1}.class, {2});";
688+
break;
689+
}
690+
sw.Write ("\t\t");
691+
sw.WriteLine (format, self.type.GetPartialAssemblyQualifiedName (cache), self.name, field);
618692
}
619693

620694
void GenerateFooter (TextWriter sw)
@@ -636,10 +710,10 @@ static string GetJavaAccess (MethodAttributes access)
636710
}
637711
}
638712

639-
static string GetJavaTypeName (TypeReference r)
713+
static string GetJavaTypeName (TypeReference r, IMetadataResolver cache)
640714
{
641715
TypeDefinition d = r.Resolve ();
642-
string jniName = JavaNativeTypeManager.ToJniName (d);
716+
string jniName = JavaNativeTypeManager.ToJniName (d, cache);
643717
if (jniName == null)
644718
Diagnostic.Error (4201, Localization.Resources.JavaCallableWrappers_XA4201, r.FullName);
645719
return jniName.Replace ('/', '.').Replace ('$', '.');
@@ -780,8 +854,19 @@ void GenerateConstructor (Signature ctor, TextWriter sw)
780854
sw.WriteLine ("\t\tandroid.util.Log.i(\"MonoDroid-Timing\", \"{0}..ctor({1}): time: \"+java.lang.System.currentTimeMillis());", name, ctor.Params);
781855
#endif
782856
if (!CannotRegisterInStaticConstructor (type)) {
783-
sw.WriteLine ("\t\tif (getClass () == {0}.class)", name);
784-
sw.WriteLine ("\t\t\tmono.android.TypeManager.Activate (\"{0}\", \"{1}\", this, new java.lang.Object[] {{ {2} }});", type.GetPartialAssemblyQualifiedName (cache), ctor.ManagedParameters, ctor.ActivateCall);
857+
string format = null;
858+
switch (CodeGenerationTarget) {
859+
case JavaPeerStyle.JavaInterop1:
860+
format = "com.xamarin.java_interop.ManagedPeer.construct (this, \"{0}\", \"{1}\", new java.lang.Object[] {{ {2} }});";
861+
break;
862+
default:
863+
format = "mono.android.TypeManager.Activate (\"{0}\", \"{1}\", this, new java.lang.Object[] {{ {2} }});";
864+
break;
865+
}
866+
sw.WriteLine ("\t\tif (getClass () == {0}.class) {", name);
867+
sw.Write ("\t\t\t");
868+
sw.WriteLine (format, type.GetPartialAssemblyQualifiedName (cache), ctor.ManagedParameters, ctor.ActivateCall);
869+
sw.WriteLine ("\t\t}");
785870
}
786871
sw.WriteLine ("\t}");
787872
}

0 commit comments

Comments
 (0)