Timothy Klenke
Timothy Klenke

Reputation: 824

Implement Generic Interface via CodeDom

The CodeDom is not generating legal VB for me when I try to implement a generic interface.

Here is my VB code to generate the VB code.

Private Sub RunTest()

    Dim compileUnit = New CodeCompileUnit

    Dim ns As New CodeNamespace()
    compileUnit.Namespaces.Add(ns)
    ns.Imports.Add(New CodeNamespaceImport("System"))
    ns.Imports.Add(New CodeNamespaceImport("System.Collections.Generic"))

    Dim fooCollection = New CodeTypeDeclaration("FooCollection")
    ns.Types.Add(fooCollection)
    fooCollection.TypeAttributes = Reflection.TypeAttributes.Public
    fooCollection.IsClass = True
    fooCollection.BaseTypes.Add(New CodeTypeReference(GetType(System.Object)))
    fooCollection.BaseTypes.Add(New CodeTypeReference( _
        "System.Collections.Generic.IEnumerable" _
        , New CodeTypeReference() {New CodeTypeReference("Foo")} _
    ))

    Dim method = New CodeMemberMethod
    fooCollection.Members.Add(method)
    method.Attributes = MemberAttributes.Private
    method.Name = "GetEnumerator"
    method.ReturnType = New CodeTypeReference( _
        "System.Collections.Generic.IEnumerable" _
        , New CodeTypeReference() {New CodeTypeReference("Foo")} _
    )
    method.PrivateImplementationType = New CodeTypeReference( _
        "System.Collections.Generic.IEnumerable" _
        , New CodeTypeReference() {New CodeTypeReference("Foo")} _
    )

    Dim provider = New Microsoft.VisualBasic.VBCodeProvider
    Dim options = New Compiler.CodeGeneratorOptions
    Dim writer = New IO.StringWriter
    provider.GenerateCodeFromCompileUnit(compileUnit, writer, options)
    Console.WriteLine(writer.ToString)

End Sub

And that will generate:

Public Class FooCollection
    Inherits Object
    Implements System.Collections.Generic.IEnumerable(Of Foo)

    Function System_Collections_Generic_IEnumerable`1_GetEnumerator() _
    As System.Collections.Generic.IEnumerable(Of Foo) _
    Implements System.Collections.Generic.IEnumerable(Of Foo).GetEnumerator

    End Function

End Class

The problem is the name of the function. The tick mark in the function name doesn't make for a legal function name.

It seems that when using the PrivateImplentationType property of the CodeMethodMethod the Name property gets used as the name of the method you are implementing, not the name of the function.

How do you explicitly set the function name or at least how do I get it to be something legal?

Upvotes: 2

Views: 671

Answers (1)

Mark Hurd
Mark Hurd

Reputation: 10931

To get a compilable output, just use ImplementationTypes: I just changed one line of your code (but I include a simple line for reference, and the corrected ReturnType):

method.Name = "GetEnumerator"
method.ReturnType = New CodeTypeReference( _
    "System.Collections.Generic.IEnumerator" _
    , New CodeTypeReference() {New CodeTypeReference("Foo")} _
)
method.ImplementationTypes.Add(New CodeTypeReference( _
    "System.Collections.Generic.IEnumerable" _
    , New CodeTypeReference() {New CodeTypeReference("Foo")} _
))

There doesn't seem to be a simple workaround using PrivateImplementationType. Microsoft's code in Microsoft.VisualBasic.VBCodeGenerator.GenerateMethod (which is in a Friend class so not easily overridden) caters for .'s, replacing them with _, but forgets to cater for ` in .NET 2.0-3.5 and (Of <type>) in 4.0. It is probably worth logging a bug at Connect, including pointing out the method name should be separately overridable compared to the method name on the interface being implemented.

You seem to need the functionality of PrivateImplementationType to support the non-generic GetEnumerator. Here is my simple adjustment of your original code to produce a single compilable library, with only warnings about empty code. This code still has "issues", such as the method.Attributes = MemberAttributes.Private being ignored where PrivateImplementationType is used...

Upvotes: 2

Related Questions