diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/AbstractClassProxyGeneratorTests.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/AbstractClassProxyGeneratorTests.cs
new file mode 100644
index 0000000000..4952905317
--- /dev/null
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/AbstractClassProxyGeneratorTests.cs
@@ -0,0 +1,188 @@
+using Amazon.JSII.Generator.Class;
+using Amazon.JSII.JsonModel.Spec;
+using Xunit;
+
+namespace Amazon.JSII.Generator.UnitTests.Class
+{
+ public class AbstractClassProxyGeneratorTests : GeneratorTestBase
+ {
+ private const string Prefix = nameof(Generator) + "." + nameof(AbstractClassProxyGenerator) + ".";
+
+ private string Render(ClassType classType)
+ {
+ Symbols.MapTypeToPackage("myFqn", classType.Assembly);
+ Symbols.MapNamespace(classType.QualifiedNamespace, "MyNamespace");
+ Symbols.MapTypeName("myFqn", "MyClass", TypeKind.Class);
+
+ var generator = new AbstractClassProxyGenerator(classType.Assembly, classType, Symbols, Namespaces);
+
+ var syntaxTree = generator.CreateSyntaxTree();
+ return syntaxTree.ToString();
+ }
+
+ [Fact(DisplayName = Prefix + nameof(IncludesAttribute))]
+ public void IncludesAttribute()
+ {
+ var classType = new ClassType
+ (
+ "myFqn",
+ "myPackage",
+ "myClass",
+ true,
+ initializer: new Method(true, false, false)
+ );
+
+ var actual = Render(classType);
+ var expected =
+ @"namespace MyNamespace
+{
+ [JsiiInterfaceProxy(typeof(MyClass), ""myFqn"")]
+ internal class MyClassProxy : MyClass
+ {
+ private MyClassProxy(ByRefValue reference): base(reference)
+ {
+ }
+ }
+}";
+ Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
+ }
+
+ [Fact(DisplayName = Prefix + nameof(IncludesDocs))]
+ public void IncludesDocs()
+ {
+ // Docs are not currently generated as part of the C# code.
+ ClassType classType = new ClassType
+ (
+ fullyQualifiedName: "myFqn",
+ assembly: "myPackage",
+ name: "myClass",
+ isAbstract: true,
+ initializer: new Method(true, false, false),
+ docs: new Docs {{"foo", "bar"}}
+ );
+
+ string actual = Render(classType);
+ string expected =
+ @"namespace MyNamespace
+{
+ /// foo: bar
+ [JsiiInterfaceProxy(typeof(MyClass), ""myFqn"")]
+ internal class MyClassProxy : MyClass
+ {
+ private MyClassProxy(ByRefValue reference): base(reference)
+ {
+ }
+ }
+}";
+ Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
+ }
+
+ [Fact(DisplayName = Prefix + nameof(IncludesProperties))]
+ public void IncludesProperties()
+ {
+ ClassType classType = new ClassType
+ (
+ fullyQualifiedName: "myFqn",
+ assembly: "myPackage",
+ name: "myClass",
+ isAbstract: true,
+ initializer: new Method(true, false, false),
+ properties: new[]
+ {
+ new Property
+ (
+ name: "myProp",
+ type: new TypeReference("myPropTypeFqn"),
+ isImmutable: false,
+ isAbstract: true,
+ isProtected: false
+ ),
+ new Property
+ (
+ name: "notMyProp",
+ type: new TypeReference("myPropTypeFqn"),
+ isImmutable: false,
+ isAbstract: false,
+ isProtected: false
+ )
+ }
+ );
+
+ Symbols.MapTypeName("myPropTypeFqn", "MyPropType", TypeKind.Class);
+ Symbols.MapPropertyName("myFqn", "myProp", "MyProp");
+
+ string actual = Render(classType);
+ string expected =
+ @"namespace MyNamespace
+{
+ [JsiiInterfaceProxy(typeof(MyClass), ""myFqn"")]
+ internal class MyClassProxy : MyClass
+ {
+ private MyClassProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ [JsiiProperty(""myProp"", ""{\""fqn\"":\""myPropTypeFqn\""}"")]
+ public override MyPropType MyProp
+ {
+ get => GetInstanceProperty();
+ set => SetInstanceProperty(value);
+ }
+ }
+}";
+ Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
+ }
+
+ [Fact(DisplayName = Prefix + nameof(IncludesMethods))]
+ public void IncludesMethods()
+ {
+ ClassType classType = new ClassType
+ (
+ fullyQualifiedName: "myFqn",
+ assembly: "myPackage",
+ name: "myClass",
+ isAbstract: true,
+ initializer: new Method(true, false, false),
+ methods: new[]
+ {
+ new Method
+ (
+ false,
+ false,
+ true,
+ name: "myMethod"
+ ),
+ new Method
+ (
+ false,
+ false,
+ false,
+ name: "notMyMethod"
+ )
+ }
+ );
+
+ Symbols.MapMethodName("myFqn", "myMethod", "MyMethod");
+
+ string actual = Render(classType);
+ string expected =
+ @"namespace MyNamespace
+{
+ [JsiiInterfaceProxy(typeof(MyClass), ""myFqn"")]
+ internal class MyClassProxy : MyClass
+ {
+ private MyClassProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ [JsiiMethod(""myMethod"", null, ""[]"")]
+ public override void MyMethod()
+ {
+ InvokeInstanceVoidMethod(new object[]{});
+ }
+ }
+}";
+ Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/ClassGeneratorTests.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/ClassGeneratorTests.cs
index 7c463047aa..f430a9b358 100644
--- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/ClassGeneratorTests.cs
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/ClassGeneratorTests.cs
@@ -1,20 +1,20 @@
using Amazon.JSII.Generator.Class;
-using Amazon.JSII.Generator.Interface;
using Amazon.JSII.JsonModel.Spec;
using Microsoft.CodeAnalysis;
using Xunit;
+using TypeKind = Amazon.JSII.JsonModel.Spec.TypeKind;
namespace Amazon.JSII.Generator.UnitTests.Class
{
public class ClassGeneratorTests : GeneratorTestBase
{
- const string Prefix = nameof(Generator) + "." + nameof(InterfaceGenerator) + ".";
+ const string Prefix = nameof(Generator) + "." + nameof(ClassGenerator) + ".";
- string Render(ClassType classType)
+ private string Render(ClassType classType)
{
Symbols.MapTypeToPackage("myFqn", classType.Assembly);
Symbols.MapNamespace(classType.QualifiedNamespace, "MyNamespace");
- Symbols.MapTypeName("myFqn", "MyClass", JsonModel.Spec.TypeKind.Class);
+ Symbols.MapTypeName("myFqn", "MyClass", TypeKind.Class);
ClassGenerator generator = new ClassGenerator(classType.Assembly, classType, Symbols, Namespaces);
@@ -36,7 +36,7 @@ public void IncludesAttribute()
string actual = Render(classType);
string expected =
-@"namespace MyNamespace
+ @"namespace MyNamespace
{
[JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")]
public class MyClass : DeputyBase
@@ -71,7 +71,7 @@ public void IncludesAbstractKeyword()
string actual = Render(classType);
string expected =
-@"namespace MyNamespace
+ @"namespace MyNamespace
{
[JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")]
public abstract class MyClass : DeputyBase
@@ -103,12 +103,12 @@ public void IncludesDocs()
name: "myClass",
isAbstract: false,
initializer: new Method(true, false, false),
- docs: new Docs { { "foo", "bar" } }
+ docs: new Docs {{"foo", "bar"}}
);
string actual = Render(classType);
string expected =
-@"namespace MyNamespace
+ @"namespace MyNamespace
{
/// foo: bar
[JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")]
@@ -144,7 +144,7 @@ public void IncludesProperties()
{
new Property
(
- name: "myProp",
+ name: "myProp",
type: new TypeReference("myPropTypeFqn"),
isImmutable: false,
isAbstract: false,
@@ -153,12 +153,12 @@ public void IncludesProperties()
}
);
- Symbols.MapTypeName("myPropTypeFqn", "MyPropType", JsonModel.Spec.TypeKind.Class);
+ Symbols.MapTypeName("myPropTypeFqn", "MyPropType", TypeKind.Class);
Symbols.MapPropertyName("myFqn", "myProp", "MyProp");
string actual = Render(classType);
string expected =
-@"namespace MyNamespace
+ @"namespace MyNamespace
{
[JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")]
public class MyClass : DeputyBase
@@ -212,7 +212,7 @@ public void IncludesMethods()
string actual = Render(classType);
string expected =
-@"namespace MyNamespace
+ @"namespace MyNamespace
{
[JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")]
public class MyClass : DeputyBase
@@ -252,11 +252,11 @@ public void IncludesBase()
@base: new TypeReference("myBaseTypeFqn")
);
- Symbols.MapTypeName("myBaseTypeFqn", "MyBaseType", JsonModel.Spec.TypeKind.Class);
+ Symbols.MapTypeName("myBaseTypeFqn", "MyBaseType", TypeKind.Class);
string actual = Render(classType);
string expected =
-@"namespace MyNamespace
+ @"namespace MyNamespace
{
[JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")]
public class MyClass : MyBaseType
@@ -294,12 +294,12 @@ public void IncludesInterfaces()
}
);
- Symbols.MapTypeName("myInterfaceFqn1", "MyInterface1", JsonModel.Spec.TypeKind.Interface);
- Symbols.MapTypeName("myInterfaceFqn2", "MyInterface2", JsonModel.Spec.TypeKind.Interface);
+ Symbols.MapTypeName("myInterfaceFqn1", "MyInterface1", TypeKind.Interface);
+ Symbols.MapTypeName("myInterfaceFqn2", "MyInterface2", TypeKind.Interface);
string actual = Render(classType);
string expected =
-@"namespace MyNamespace
+ @"namespace MyNamespace
{
[JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")]
public class MyClass : DeputyBase, IMyInterface1, IMyInterface2
@@ -320,4 +320,4 @@ protected MyClass(DeputyProps props): base(props)
Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
}
}
-}
+}
\ No newline at end of file
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/SymbolMapExtensions.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/SymbolMapExtensions.cs
index 4d2bd4cb2d..ed6093e7fa 100644
--- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/SymbolMapExtensions.cs
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/SymbolMapExtensions.cs
@@ -1,7 +1,6 @@
using Amazon.JSII.JsonModel.Spec;
using NSubstitute;
using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
-using Type = Amazon.JSII.JsonModel.Spec.Type;
namespace Amazon.JSII.Generator.UnitTests
{
@@ -91,6 +90,15 @@ public static void MapTypeName(this ISymbolMap symbols, string fullyQualifiedNam
frameworkName = $"I{frameworkName}";
}
+ if (kind == TypeKind.Class)
+ {
+ string proxyName = $"{frameworkName}Proxy";
+
+ symbols
+ .GetAbstractClassProxyName(Arg.Is(t => t.FullyQualifiedName == fullyQualifiedName), disambiguate: Arg.Any())
+ .Returns(proxyName);
+ }
+
symbols
.GetName(Arg.Is(t => t.FullyQualifiedName == fullyQualifiedName), disambiguate: Arg.Any())
.Returns(frameworkName);
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/AssemblyGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/AssemblyGenerator.cs
index d05786067c..6e087b8d45 100644
--- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/AssemblyGenerator.cs
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/AssemblyGenerator.cs
@@ -281,25 +281,47 @@ void SaveType(Type type)
switch (type.Kind)
{
case TypeKind.Class:
- SaveTypeFile($"{symbols.GetName(type)}.cs", new ClassGenerator(assembly.Name, (ClassType)type, symbols).CreateSyntaxTree());
+ {
+ var classType = (ClassType) type;
+
+ if (classType.IsAbstract)
+ {
+ SaveTypeFile($"{symbols.GetAbstractClassProxyName(classType)}.cs",
+ new AbstractClassProxyGenerator(assembly.Name, classType, symbols).CreateSyntaxTree());
+ }
+
+ SaveTypeFile($"{symbols.GetName(type)}.cs",
+ new ClassGenerator(assembly.Name, classType, symbols).CreateSyntaxTree());
return;
+ }
case TypeKind.Enum:
- SaveTypeFile($"{symbols.GetName(type)}.cs", new EnumGenerator(assembly.Name, (EnumType)type, symbols).CreateSyntaxTree());
+ {
+ SaveTypeFile($"{symbols.GetName(type)}.cs",
+ new EnumGenerator(assembly.Name, (EnumType) type, symbols).CreateSyntaxTree());
return;
+ }
case TypeKind.Interface:
- InterfaceType interfaceType = (InterfaceType)type;
+ {
+ InterfaceType interfaceType = (InterfaceType) type;
- SaveTypeFile($"{symbols.GetName(interfaceType)}.cs", new InterfaceGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree());
- SaveTypeFile($"{symbols.GetInterfaceProxyName(interfaceType)}.cs", new InterfaceProxyGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree());
+ SaveTypeFile($"{symbols.GetName(interfaceType)}.cs",
+ new InterfaceGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree());
+ SaveTypeFile($"{symbols.GetInterfaceProxyName(interfaceType)}.cs",
+ new InterfaceProxyGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree());
if (interfaceType.IsDataType == true)
{
- SaveTypeFile($"{symbols.GetInterfaceDefaultName(interfaceType)}.cs", new InterfaceDefaultGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree());
+ SaveTypeFile($"{symbols.GetInterfaceDefaultName(interfaceType)}.cs",
+ new InterfaceDefaultGenerator(assembly.Name, interfaceType, symbols)
+ .CreateSyntaxTree());
}
return;
+ }
default:
+ {
throw new ArgumentException($"Unkown type kind: {type.Kind}", nameof(type));
+ }
}
void SaveTypeFile(string filename, SyntaxTree syntaxTree)
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyGenerator.cs
new file mode 100644
index 0000000000..d4549f2fad
--- /dev/null
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyGenerator.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Amazon.JSII.JsonModel.Spec;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+using Type = Amazon.JSII.JsonModel.Spec.Type;
+
+namespace Amazon.JSII.Generator.Class
+{
+ public class AbstractClassProxyGenerator : TypeProxyGeneratorBase
+ {
+ public AbstractClassProxyGenerator(string package, ClassType type, ISymbolMap symbols,
+ INamespaceSet namespaces = null)
+ : base(package, type, symbols, namespaces)
+ {
+ if (!type.IsAbstract)
+ {
+ throw new ArgumentException("Class type must be abstract.", nameof(type));
+ }
+ }
+
+ protected override SyntaxToken GetProxyTypeNameSyntax()
+ {
+ return SF.Identifier(Symbols.GetAbstractClassProxyName(Type));
+ }
+
+ protected override IEnumerable CreateProperties()
+ {
+ foreach (Property property in GetAllProperties(Type))
+ {
+ var generator = new AbstractClassProxyPropertyGenerator(Type, property, Symbols, Namespaces);
+ yield return generator.CreateProperty();
+ }
+ }
+
+ protected override IEnumerable CreateMethods()
+ {
+ foreach (Method method in GetAllMethods(Type))
+ {
+ var generator = new AbstractClassProxyMethodGenerator(Type, method, Symbols, Namespaces);
+ yield return generator.CreateMethod();
+ }
+ }
+
+ private IEnumerable GetAllMethods(Type type)
+ {
+ IEnumerable GetAllMethodsRecurse(Type currentType, IEnumerable methods)
+ {
+ if (currentType is InterfaceType interfaceType)
+ {
+ methods = methods.Concat(interfaceType.Methods ?? new Method[0]);
+
+ if (interfaceType.Interfaces != null)
+ {
+ var superinterfaceMethods = interfaceType.Interfaces.Select(r =>
+ Symbols.GetTypeFromFullyQualifiedName(r.FullyQualifiedName) as
+ InterfaceType)
+ .SelectMany(i => GetAllMethodsRecurse(i, methods))
+ .ToList();
+
+ methods = methods.Concat(superinterfaceMethods);
+ }
+ }
+ else if (currentType is ClassType classType)
+ {
+ methods = methods.Concat(classType.Methods ?? new Method[0]);
+
+ if (classType.Interfaces != null)
+ {
+ var superinterfaceMethods = classType.Interfaces.Select(r =>
+ Symbols.GetTypeFromFullyQualifiedName(r.FullyQualifiedName) as
+ InterfaceType)
+ .SelectMany(i => GetAllMethodsRecurse(i, methods))
+ .ToList();
+
+ methods = methods.Concat(superinterfaceMethods);
+ }
+
+ if (classType.Base != null)
+ {
+ methods = methods.Concat(GetAllMethodsRecurse(
+ Symbols.GetTypeFromFullyQualifiedName(classType.Base.FullyQualifiedName) as ClassType,
+ methods));
+ }
+ }
+
+ return methods;
+ }
+
+ return GetAllMethodsRecurse(type, new List())
+ .GroupBy(m => (m.Name,
+ string.Join("",
+ m.Parameters?.Select(p => p.Name + p.Type.FullyQualifiedName) ?? Enumerable.Empty())))
+ .Select(g => g.First())
+ .Where(m => m.IsAbstract ?? false);
+ }
+
+ private IEnumerable GetAllProperties(Type type)
+ {
+ IEnumerable GetAllPropertiesRecurse(Type currentType, IEnumerable properties)
+ {
+ if (currentType is InterfaceType interfaceType)
+ {
+ properties = properties.Concat(interfaceType.Properties ?? new Property[0]);
+
+ if (interfaceType.Interfaces != null)
+ {
+ var superinterfaceMethods = interfaceType.Interfaces.Select(r =>
+ Symbols.GetTypeFromFullyQualifiedName(r.FullyQualifiedName) as
+ InterfaceType)
+ .SelectMany(i => GetAllPropertiesRecurse(i, properties))
+ .ToList();
+
+ properties = properties.Concat(superinterfaceMethods);
+ }
+ }
+ else if (currentType is ClassType classType)
+ {
+ properties =
+ properties.Concat(classType.Properties ?? new Property[0]);
+
+ if (classType.Interfaces != null)
+ {
+ var superinterfaceMethods = classType.Interfaces.Select(r =>
+ Symbols.GetTypeFromFullyQualifiedName(r.FullyQualifiedName) as
+ InterfaceType)
+ .SelectMany(i => GetAllPropertiesRecurse(i, properties))
+ .ToList();
+
+ properties = properties.Concat(superinterfaceMethods);
+ }
+
+ if (classType.Base != null)
+ {
+ properties = properties.Concat(GetAllPropertiesRecurse(
+ Symbols.GetTypeFromFullyQualifiedName(classType.Base.FullyQualifiedName) as ClassType,
+ properties));
+ }
+ }
+
+ return properties;
+ }
+
+ return GetAllPropertiesRecurse(type, new List())
+ .GroupBy(p => p.Name)
+ .Select(g => g.First())
+ .Where(p => p.IsAbstract ?? false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyMethodGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyMethodGenerator.cs
new file mode 100644
index 0000000000..f1114309b7
--- /dev/null
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyMethodGenerator.cs
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+using Amazon.JSII.JsonModel.Spec;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+
+namespace Amazon.JSII.Generator.Class
+{
+ public class AbstractClassProxyMethodGenerator : ClassMethodGenerator
+ {
+ public AbstractClassProxyMethodGenerator(ClassType type, Method method, ISymbolMap symbols,
+ INamespaceSet namespaces) : base(type, method, symbols, namespaces)
+ {
+ }
+
+ protected override IEnumerable GetModifierKeywords()
+ {
+ yield return Method.IsProtected ? SyntaxKind.ProtectedKeyword : SyntaxKind.PublicKeyword;
+ // Abstract class proxies can only contain overwritten members.
+ yield return SyntaxKind.OverrideKeyword;
+ }
+
+ protected override BlockSyntax GetBody()
+ {
+ if (Method.Returns == null)
+ {
+ return SF.Block(SF.ExpressionStatement(CreateInvocationExpression()));
+ }
+
+ return SF.Block(SF.ReturnStatement(CreateInvocationExpression()));
+ }
+
+ protected override bool HasSemicolon => false;
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyPropertyGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyPropertyGenerator.cs
new file mode 100644
index 0000000000..13be50b533
--- /dev/null
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyPropertyGenerator.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using Amazon.JSII.JsonModel.Spec;
+using Microsoft.CodeAnalysis.CSharp;
+
+namespace Amazon.JSII.Generator.Class
+{
+ public class AbstractClassProxyPropertyGenerator : ClassPropertyGenerator
+ {
+ public AbstractClassProxyPropertyGenerator(ClassType type, Property property, ISymbolMap symbols,
+ INamespaceSet namespaces) : base(type, property, symbols, namespaces)
+ {
+ }
+
+ protected override IEnumerable GetModifierKeywords()
+ {
+ yield return Property.IsProtected == true ? SyntaxKind.ProtectedKeyword : SyntaxKind.PublicKeyword;
+ // Abstract class proxies can only contain overwritten members.
+ yield return SyntaxKind.OverrideKeyword;
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/ClassMethodGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/ClassMethodGenerator.cs
index 8108c3d091..074bdf3abb 100644
--- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/ClassMethodGenerator.cs
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/ClassMethodGenerator.cs
@@ -1,10 +1,8 @@
-using Amazon.JSII.JsonModel.Spec;
-using Microsoft.CodeAnalysis;
+using System.Collections.Generic;
+using System.Linq;
+using Amazon.JSII.JsonModel.Spec;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using System;
-using System.Collections.Generic;
-using System.Linq;
using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Amazon.JSII.Generator.Class
@@ -16,15 +14,15 @@ public ClassMethodGenerator(ClassType type, Method method, ISymbolMap symbols, I
{
}
- bool IsDefinedOnAncestor
+ private bool IsDefinedOnAncestor
{
get
{
- string[] objectMethods = new[]
+ string[] objectMethods =
{
"ToString",
"GetHashCode",
- "Equals",
+ "Equals"
};
if (objectMethods.Contains(NameUtils.ConvertMethodName(Method.Name)))
@@ -79,4 +77,4 @@ protected override BlockSyntax GetBody()
protected override bool HasSemicolon => Method.IsAbstract == true;
}
-}
+}
\ No newline at end of file
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/ISymbolMap.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/ISymbolMap.cs
index d60230587f..030170385a 100644
--- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/ISymbolMap.cs
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/ISymbolMap.cs
@@ -15,6 +15,8 @@ public interface ISymbolMap
string GetName(Type type, bool disambiguate = false);
string GetName(string fullyQualifiedName, bool disambiguate = false);
+
+ string GetAbstractClassProxyName(ClassType type, bool disambiguate = false);
string GetInterfaceProxyName(InterfaceType type, bool disambiguate = false);
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Interface/InterfaceProxyGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Interface/InterfaceProxyGenerator.cs
index 9935708ce0..d4b806f0cf 100644
--- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Interface/InterfaceProxyGenerator.cs
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Interface/InterfaceProxyGenerator.cs
@@ -1,98 +1,24 @@
-using Amazon.JSII.JsonModel.Spec;
+using System.Collections.Generic;
+using Amazon.JSII.JsonModel.Spec;
using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using System;
-using System.Collections.Generic;
-using System.Linq;
using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Amazon.JSII.Generator.Interface
{
- public class InterfaceProxyGenerator : TypeGeneratorBase
+ public class InterfaceProxyGenerator : TypeProxyGeneratorBase
{
public InterfaceProxyGenerator(string package, InterfaceType type, ISymbolMap symbols, INamespaceSet namespaces = null)
: base(package, type, symbols, namespaces)
{
}
-
- protected override MemberDeclarationSyntax CreateType()
- {
- return SF.ClassDeclaration
- (
- CreateAttributes(),
- SF.TokenList(SF.Token(SyntaxKind.InternalKeyword)),
- GetProxyTypeNameSyntax(),
- null,
- CreateBaseList(),
- SF.List(),
- SF.List(CreateMembers())
- );
-
- SyntaxList CreateAttributes()
- {
- TypeOfExpressionSyntax typeOfExpression = SF.TypeOfExpression(Symbols.GetNameSyntax(Type));
- SyntaxToken fullyQualifiedNameLiteral = SF.Literal(Type.FullyQualifiedName);
-
- return SF.List(new[] {
- SF.AttributeList(SF.SeparatedList(new[] {
- SF.Attribute(
- SF.ParseName("JsiiInterfaceProxy"),
- SF.ParseAttributeArgumentList($"({typeOfExpression}, {fullyQualifiedNameLiteral})")
- )
- }))
- });
- }
-
- BaseListSyntax CreateBaseList()
- {
- return SF.BaseList(SF.SeparatedList(GetBaseTypes()));
-
- IEnumerable GetBaseTypes()
- {
- yield return SF.SimpleBaseType(SF.ParseTypeName("DeputyBase"));
-
- Namespaces.Add(Type);
- yield return SF.SimpleBaseType(Symbols.GetNameSyntax(Type, disambiguate: true));
- }
- }
-
- IEnumerable CreateMembers()
- {
- return CreateConstructors()
- .Concat(CreateProperties())
- .Concat(CreateMethods());
- }
- }
-
- SyntaxToken GetProxyTypeNameSyntax()
+
+ protected override SyntaxToken GetProxyTypeNameSyntax()
{
return SF.Identifier(Symbols.GetInterfaceProxyName(Type));
}
- IEnumerable CreateConstructors()
- {
- yield return SF.ConstructorDeclaration
- (
- SF.List(),
-
- // Only Amazon.JSII.Runtime should create interface proxies,
- // so we make the constructor private.
- SF.TokenList(SF.Token(SyntaxKind.PrivateKeyword)),
-
- GetProxyTypeNameSyntax(),
- SF.ParseParameterList("(ByRefValue reference)"),
- SF.ConstructorInitializer
- (
- SyntaxKind.BaseConstructorInitializer,
- SF.ParseArgumentList("(reference)")
- ),
- SF.Block(),
- null
- );
- }
-
- IEnumerable CreateProperties()
+ protected override IEnumerable CreateProperties()
{
foreach (Property property in Type.GetAllProperties(Symbols))
{
@@ -101,7 +27,7 @@ IEnumerable CreateProperties()
}
}
- IEnumerable CreateMethods()
+ protected override IEnumerable CreateMethods()
{
foreach (Method method in Type.GetAllMethods(Symbols))
{
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/SymbolMap.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/SymbolMap.cs
index f00914887b..eb5a9a3175 100644
--- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/SymbolMap.cs
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/SymbolMap.cs
@@ -54,16 +54,26 @@ TypeMetadata GetMetadata(Type type)
switch (type.Kind)
{
case JsonModel.Spec.TypeKind.Class:
+ {
+ var classType = (ClassType) type;
+ if (classType.IsAbstract)
+ {
+ return new AbstractClassTypeMetadata(classType, assembly);
+ }
return new ClassTypeMetadata((ClassType)type, assembly);
-
+ }
case JsonModel.Spec.TypeKind.Enum:
- return new EnumTypeMetadata((EnumType)type, assembly);
-
+ {
+ return new EnumTypeMetadata((EnumType)type, assembly);
+ }
case JsonModel.Spec.TypeKind.Interface:
- return new InterfaceTypeMetadata((InterfaceType)type, assembly);
-
+ {
+ return new InterfaceTypeMetadata((InterfaceType)type, assembly);
+ }
default:
- throw new ArgumentException($"Type {type.Name} has unrecognized kind {type.Kind}", nameof(type));
+ {
+ throw new ArgumentException($"Type {type.Name} has unrecognized kind {type.Kind}", nameof(type));
+ }
}
}
}
@@ -101,6 +111,18 @@ public string GetName(string fullyQualifiedName, bool disambiguate = false)
return GetName(GetTypeFromFullyQualifiedName(fullyQualifiedName), disambiguate);
}
+ public string GetAbstractClassProxyName(ClassType type, bool disambiguate = false)
+ {
+ type = type ?? throw new ArgumentNullException(nameof(type));
+
+ if (_types[type.FullyQualifiedName] is AbstractClassTypeMetadata metadata)
+ {
+ return metadata.ProxyName;
+ }
+
+ throw new ArgumentException($"Cannot get proxy name for '{type.FullyQualifiedName}' because it is not an abstract class.");
+ }
+
public string GetInterfaceProxyName(InterfaceType type, bool disambiguate = false)
{
type = type ?? throw new ArgumentNullException(nameof(type));
@@ -110,7 +132,7 @@ public string GetInterfaceProxyName(InterfaceType type, bool disambiguate = fals
return metadata.ProxyName;
}
- throw new ArgumentException($"Cannot get proxy name for '{type.FullyQualifiedName}' because it is not an interface");
+ throw new ArgumentException($"Cannot get proxy name for '{type.FullyQualifiedName}' because it is not an interface.");
}
public string GetInterfaceDefaultName(InterfaceType type, bool disambiguate = false)
@@ -122,7 +144,7 @@ public string GetInterfaceDefaultName(InterfaceType type, bool disambiguate = fa
return metadata.DefaultName;
}
- throw new ArgumentException($"Cannot get default name for '{type.FullyQualifiedName}' because it is not an interface");
+ throw new ArgumentException($"Cannot get default name for '{type.FullyQualifiedName}' because it is not an interface.");
}
public string GetName(Type type, Method method)
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeMetadata.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeMetadata.cs
index 462930882e..f6f7af256b 100644
--- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeMetadata.cs
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeMetadata.cs
@@ -67,6 +67,31 @@ public ClassTypeMetadata(ClassType type, Assembly assembly)
}
}
+ public class AbstractClassTypeMetadata : ClassTypeMetadata
+ {
+ public string ProxyName { get; private set; }
+
+ public string FrameworkFullyQualifiedProxyName => $"{Namespace}.{ProxyName}";
+
+ public AbstractClassTypeMetadata(ClassType type, Assembly assembly)
+ : base(type, assembly)
+ {
+ ProxyName = $"{Name}Proxy";
+ }
+
+ public override void ResolveTypeNameConflicts(ISet namespaceNames)
+ {
+ base.ResolveTypeNameConflicts(namespaceNames);
+
+ ISet memberNames = new HashSet(MemberNames.Values);
+
+ while (memberNames.Contains(ProxyName) || namespaceNames.Contains(FrameworkFullyQualifiedProxyName))
+ {
+ ProxyName += "_";
+ }
+ }
+ }
+
public class EnumTypeMetadata : TypeMetadata
{
public EnumTypeMetadata(EnumType type, Assembly assembly)
@@ -82,7 +107,6 @@ public EnumTypeMetadata(EnumType type, Assembly assembly)
MemberNames = new ReadOnlyDictionary(memberNames);
Name = NameUtils.ConvertTypeName(type.Name);
}
-
}
public class InterfaceTypeMetadata : TypeMetadata
diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeProxyGeneratorBase.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeProxyGeneratorBase.cs
new file mode 100644
index 0000000000..5060c8f6f7
--- /dev/null
+++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeProxyGeneratorBase.cs
@@ -0,0 +1,101 @@
+using System.Collections.Generic;
+using System.Linq;
+using Amazon.JSII.JsonModel.Spec;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+
+namespace Amazon.JSII.Generator
+{
+ public abstract class TypeProxyGeneratorBase : TypeGeneratorBase where T : Type
+ {
+ protected TypeProxyGeneratorBase(string package, T type, ISymbolMap symbols, INamespaceSet namespaces)
+ : base(package, type, symbols, namespaces)
+ {
+ }
+
+ protected override MemberDeclarationSyntax CreateType()
+ {
+ return SF.ClassDeclaration
+ (
+ CreateAttributes(),
+ SF.TokenList(SF.Token(SyntaxKind.InternalKeyword)),
+ GetProxyTypeNameSyntax(),
+ null,
+ CreateBaseList(),
+ SF.List(),
+ SF.List(CreateMembers())
+ );
+
+ SyntaxList CreateAttributes()
+ {
+ var typeOfExpression = SF.TypeOfExpression(Symbols.GetNameSyntax(Type));
+ var fullyQualifiedNameLiteral = SF.Literal(Type.FullyQualifiedName);
+
+ return SF.List(new[]
+ {
+ SF.AttributeList(SF.SeparatedList(new[]
+ {
+ SF.Attribute(
+ SF.ParseName("JsiiInterfaceProxy"),
+ SF.ParseAttributeArgumentList($"({typeOfExpression}, {fullyQualifiedNameLiteral})")
+ )
+ }))
+ });
+ }
+
+ BaseListSyntax CreateBaseList()
+ {
+ return SF.BaseList(SF.SeparatedList(GetBaseTypes()));
+
+ IEnumerable GetBaseTypes()
+ {
+ if (IsImplementingInterface)
+ {
+ yield return SF.SimpleBaseType(SF.ParseTypeName("DeputyBase"));
+ }
+
+ Namespaces.Add(Type);
+ yield return SF.SimpleBaseType(Symbols.GetNameSyntax(Type, disambiguate: true));
+ }
+ }
+
+ IEnumerable CreateMembers()
+ {
+ return CreateConstructors()
+ .Concat(CreateProperties())
+ .Concat(CreateMethods());
+ }
+ }
+
+ protected virtual IEnumerable CreateConstructors()
+ {
+ yield return SF.ConstructorDeclaration
+ (
+ SF.List(),
+
+ // Only Amazon.JSII.Runtime should create interface proxies,
+ // so we make the constructor private.
+ SF.TokenList(SF.Token(SyntaxKind.PrivateKeyword)),
+ GetProxyTypeNameSyntax(),
+ SF.ParseParameterList("(ByRefValue reference)"),
+ SF.ConstructorInitializer
+ (
+ SyntaxKind.BaseConstructorInitializer,
+ SF.ParseArgumentList("(reference)")
+ ),
+ SF.Block(),
+ null
+ );
+ }
+
+ private bool IsImplementingInterface => Type is InterfaceType;
+
+ protected abstract SyntaxToken GetProxyTypeNameSyntax();
+
+ protected abstract IEnumerable CreateProperties();
+
+ protected abstract IEnumerable CreateMethods();
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/ValueConverter.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/ValueConverter.cs
index 58a14fc5dd..af5e834506 100644
--- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/ValueConverter.cs
+++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/ValueConverter.cs
@@ -115,7 +115,7 @@ bool IsReferenceType()
return
_types.GetClassType(fullyQualifiedName) != null ||
_types.GetInterfaceType(fullyQualifiedName) != null ||
- _types.GetInterfaceProxyType(fullyQualifiedName) != null;
+ _types.GetProxyType(fullyQualifiedName) != null;
}
}
diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ITypeCache.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ITypeCache.cs
index 3d6d3cfbf9..b5c86bb9b1 100644
--- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ITypeCache.cs
+++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ITypeCache.cs
@@ -10,7 +10,7 @@ public interface ITypeCache
Type GetInterfaceType(string fullyQualifiedName);
- Type GetInterfaceProxyType(string fullyQualifiedName);
+ Type GetProxyType(string fullyQualifiedName);
Type GetFrameworkType(JsonModel.Spec.TypeReference reference);
}
diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ReferenceMap.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ReferenceMap.cs
index 0b8c171906..2e0ff6cdd5 100644
--- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ReferenceMap.cs
+++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ReferenceMap.cs
@@ -1,8 +1,8 @@
-using Amazon.JSII.JsonModel.Api;
-using Amazon.JSII.Runtime.Deputy;
-using System;
+using System;
using System.Collections.Generic;
using System.Reflection;
+using Amazon.JSII.JsonModel.Api;
+using Amazon.JSII.Runtime.Deputy;
namespace Amazon.JSII.Runtime.Services
{
@@ -20,7 +20,9 @@ public void AddNativeReference(ByRefValue reference, DeputyBase nativeReference)
{
if (_references.ContainsKey(reference.Value))
{
- throw new ArgumentException($"Cannot add reference for {reference.Value}: A reference with this name already exists", nameof(reference));
+ throw new ArgumentException(
+ $"Cannot add reference for {reference.Value}: A reference with this name already exists",
+ nameof(reference));
}
_references[reference.Value] = nativeReference;
@@ -36,7 +38,7 @@ public DeputyBase GetOrCreateNativeReference(ByRefValue byRefValue)
if (!_references.ContainsKey(byRefValue.Value))
{
ConstructorInfo constructorInfo = GetByRefConstructor();
- _references[byRefValue.Value] = (DeputyBase)constructorInfo.Invoke(new object[] { byRefValue });
+ _references[byRefValue.Value] = (DeputyBase) constructorInfo.Invoke(new object[] {byRefValue});
}
return _references[byRefValue.Value];
@@ -46,8 +48,9 @@ ConstructorInfo GetByRefConstructor()
Type type = _types.GetClassType(byRefValue.FullyQualifiedName);
if (type == null)
{
- type = _types.GetInterfaceProxyType(byRefValue.FullyQualifiedName);
+ type = _types.GetProxyType(byRefValue.FullyQualifiedName);
}
+
if (type == null)
{
throw new ArgumentException(
@@ -58,8 +61,14 @@ ConstructorInfo GetByRefConstructor()
BindingFlags constructorFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
- return type.GetConstructor(constructorFlags, null, new[] { typeof(ByRefValue) }, null);
+ // Get proxy class implementation for abstract types.
+ if (type.IsClass && type.IsAbstract)
+ {
+ type = _types.GetProxyType(byRefValue.FullyQualifiedName);
+ }
+
+ return type.GetConstructor(constructorFlags, null, new[] {typeof(ByRefValue)}, null);
}
}
}
-}
+}
\ No newline at end of file
diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/TypeCache.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/TypeCache.cs
index b0a5fac060..c3f5af4a3e 100644
--- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/TypeCache.cs
+++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/TypeCache.cs
@@ -1,11 +1,13 @@
-using Microsoft.Extensions.Logging;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
-using PrimitiveType = Amazon.JSII.JsonModel.Spec.PrimitiveType;
-using CollectionKind = Amazon.JSII.JsonModel.Spec.CollectionKind;
+using Amazon.JSII.JsonModel.Spec;
using Amazon.JSII.Runtime.Deputy;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json.Linq;
+using Assembly = System.Reflection.Assembly;
+using Type = System.Type;
namespace Amazon.JSII.Runtime.Services
{
@@ -42,12 +44,12 @@ public Type GetInterfaceType(string fullyQualifiedName)
return GetType(fullyQualifiedName);
}
- public Type GetInterfaceProxyType(string fullyQualifiedName)
+ public Type GetProxyType(string fullyQualifiedName)
{
return GetType(fullyQualifiedName + ProxySuffix);
}
- public Type GetFrameworkType(JsonModel.Spec.TypeReference reference)
+ public Type GetFrameworkType(TypeReference reference)
{
bool isOptional = reference.IsOptional == true;
@@ -79,7 +81,7 @@ public Type GetFrameworkType(JsonModel.Spec.TypeReference reference)
case PrimitiveType.Date:
return MakeNullableIfOptional(typeof(DateTime));
case PrimitiveType.Json:
- return typeof(Newtonsoft.Json.Linq.JObject);
+ return typeof(JObject);
case PrimitiveType.Number:
return MakeNullableIfOptional(typeof(double));
case PrimitiveType.String:
diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon/JSII/Tests/CalculatorNamespace/BaseNamespace/BaseProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon/JSII/Tests/CalculatorNamespace/BaseNamespace/BaseProxy.cs
new file mode 100644
index 0000000000..c6a14e4a18
--- /dev/null
+++ b/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon/JSII/Tests/CalculatorNamespace/BaseNamespace/BaseProxy.cs
@@ -0,0 +1,13 @@
+using Amazon.JSII.Runtime.Deputy;
+
+namespace Amazon.JSII.Tests.CalculatorNamespace.BaseNamespace
+{
+ /// A base class.
+ [JsiiInterfaceProxy(typeof(Base), "@scope/jsii-calc-base.Base")]
+ internal class BaseProxy : Base
+ {
+ private BaseProxy(ByRefValue reference): base(reference)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/OperationProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/OperationProxy.cs
new file mode 100644
index 0000000000..738b688952
--- /dev/null
+++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/OperationProxy.cs
@@ -0,0 +1,27 @@
+using Amazon.JSII.Runtime.Deputy;
+
+namespace Amazon.JSII.Tests.CalculatorNamespace.LibNamespace
+{
+ /// Represents an operation on values.
+ [JsiiInterfaceProxy(typeof(Operation), "@scope/jsii-calc-lib.Operation")]
+ internal class OperationProxy : Operation
+ {
+ private OperationProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ /// The value.
+ [JsiiProperty("value", "{\"primitive\":\"number\"}")]
+ public override double Value
+ {
+ get => GetInstanceProperty();
+ }
+
+ /// String representation of the value.
+ [JsiiMethod("toString", "{\"primitive\":\"string\"}", "[]")]
+ public override string ToString()
+ {
+ return InvokeInstanceMethod(new object[]{});
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/ValueProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/ValueProxy.cs
new file mode 100644
index 0000000000..4042a5ed31
--- /dev/null
+++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/ValueProxy.cs
@@ -0,0 +1,20 @@
+using Amazon.JSII.Runtime.Deputy;
+
+namespace Amazon.JSII.Tests.CalculatorNamespace.LibNamespace
+{
+ /// Abstract class which represents a numeric value.
+ [JsiiInterfaceProxy(typeof(Value_), "@scope/jsii-calc-lib.Value")]
+ internal class ValueProxy : Value_
+ {
+ private ValueProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ /// The value.
+ [JsiiProperty("value", "{\"primitive\":\"number\"}")]
+ public override double Value
+ {
+ get => GetInstanceProperty();
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassBaseProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassBaseProxy.cs
new file mode 100644
index 0000000000..e18268ad8a
--- /dev/null
+++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassBaseProxy.cs
@@ -0,0 +1,18 @@
+using Amazon.JSII.Runtime.Deputy;
+
+namespace Amazon.JSII.Tests.CalculatorNamespace
+{
+ [JsiiInterfaceProxy(typeof(AbstractClassBase), "jsii-calc.AbstractClassBase")]
+ internal class AbstractClassBaseProxy : AbstractClassBase
+ {
+ private AbstractClassBaseProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ [JsiiProperty("abstractProperty", "{\"primitive\":\"string\"}")]
+ public override string AbstractProperty
+ {
+ get => GetInstanceProperty();
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassProxy.cs
new file mode 100644
index 0000000000..0640ddc205
--- /dev/null
+++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassProxy.cs
@@ -0,0 +1,24 @@
+using Amazon.JSII.Runtime.Deputy;
+
+namespace Amazon.JSII.Tests.CalculatorNamespace
+{
+ [JsiiInterfaceProxy(typeof(AbstractClass), "jsii-calc.AbstractClass")]
+ internal class AbstractClassProxy : AbstractClass
+ {
+ private AbstractClassProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ [JsiiProperty("abstractProperty", "{\"primitive\":\"string\"}")]
+ public override string AbstractProperty
+ {
+ get => GetInstanceProperty();
+ }
+
+ [JsiiMethod("abstractMethod", "{\"primitive\":\"string\"}", "[{\"name\":\"name\",\"type\":{\"primitive\":\"string\"}}]")]
+ public override string AbstractMethod(string name)
+ {
+ return InvokeInstanceMethod(new object[]{name});
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/BinaryOperationProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/BinaryOperationProxy.cs
new file mode 100644
index 0000000000..0b057a43c8
--- /dev/null
+++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/BinaryOperationProxy.cs
@@ -0,0 +1,27 @@
+using Amazon.JSII.Runtime.Deputy;
+
+namespace Amazon.JSII.Tests.CalculatorNamespace
+{
+ /// Represents an operation with two operands.
+ [JsiiInterfaceProxy(typeof(BinaryOperation), "jsii-calc.BinaryOperation")]
+ internal class BinaryOperationProxy : BinaryOperation
+ {
+ private BinaryOperationProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ /// The value.
+ [JsiiProperty("value", "{\"primitive\":\"number\"}")]
+ public override double Value
+ {
+ get => GetInstanceProperty();
+ }
+
+ /// String representation of the value.
+ [JsiiMethod("toString", "{\"primitive\":\"string\"}", "[]")]
+ public override string ToString()
+ {
+ return InvokeInstanceMethod(new object[]{});
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnaryOperationProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnaryOperationProxy.cs
new file mode 100644
index 0000000000..2d748b3b58
--- /dev/null
+++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnaryOperationProxy.cs
@@ -0,0 +1,27 @@
+using Amazon.JSII.Runtime.Deputy;
+
+namespace Amazon.JSII.Tests.CalculatorNamespace
+{
+ /// An operation on a single operand.
+ [JsiiInterfaceProxy(typeof(UnaryOperation), "jsii-calc.UnaryOperation")]
+ internal class UnaryOperationProxy : UnaryOperation
+ {
+ private UnaryOperationProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ /// The value.
+ [JsiiProperty("value", "{\"primitive\":\"number\"}")]
+ public override double Value
+ {
+ get => GetInstanceProperty();
+ }
+
+ /// String representation of the value.
+ [JsiiMethod("toString", "{\"primitive\":\"string\"}", "[]")]
+ public override string ToString()
+ {
+ return InvokeInstanceMethod(new object[]{});
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/composition/CompositeOperationProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/composition/CompositeOperationProxy.cs
new file mode 100644
index 0000000000..6507f39c74
--- /dev/null
+++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/composition/CompositeOperationProxy.cs
@@ -0,0 +1,24 @@
+using Amazon.JSII.Runtime.Deputy;
+using Amazon.JSII.Tests.CalculatorNamespace.LibNamespace;
+
+namespace Amazon.JSII.Tests.CalculatorNamespace.composition
+{
+ /// Abstract operation composed from an expression of other operations.
+ [JsiiInterfaceProxy(typeof(CompositeOperation_), "jsii-calc.composition.CompositeOperation")]
+ internal class CompositeOperationProxy : CompositeOperation_
+ {
+ private CompositeOperationProxy(ByRefValue reference): base(reference)
+ {
+ }
+
+ ///
+ /// The expression that this operation consists of.
+ /// Must be implemented by derived classes.
+ ///
+ [JsiiProperty("expression", "{\"fqn\":\"@scope/jsii-calc-lib.Value\"}")]
+ public override Value_ Expression
+ {
+ get => GetInstanceProperty();
+ }
+ }
+}
\ No newline at end of file