6

I am replicating a situation that I am facing.

Let's say we have an assembly, with C# class as:

public class Program
{
    int n = 0;

    public void Print()
    {
        Console.WriteLine(n);
    }

    public Program()
    {
    }

    public Program(int num = 10)
    {
        n = num;
    }
}

We refer the above assembly in VB.NET project and trying to create an instance of the Program class:

Module Module1 
    Sub Main()
        Dim p As New Program()
        p.Print()
        p = New Program(20)
        p.Print()
        Console.ReadLine()
    End Sub
End Module

The VB.NET project is not compiling, giving error:

'.ctor' is ambiguous because multiple kinds of members with this name exist in class 'ConsoleApplication2.Program'.

From the error message we can see the the VB.NET compiler is not sure which constructor to call - as one constructor is parameterless and other with one optional parameter. This issue is occurring in VS2010/.NET 4 and not in VS2012/.NET 4.5. Also in C# it is not givng any issues, it successfully compiles and runs the code of object initiaization of Program class.

Is there a way we can create Program class' instance in VB.NET + VS2010/.NET 4 without changing the constructors ?

Brij
  • 11,731
  • 22
  • 78
  • 116
  • 2
    Why do you want this construct? Is there a way that I'm missing that you can actually invoke the second constructor and have the compiler use the default parameter? – Damien_The_Unbeliever Feb 20 '14 at 10:24
  • This code smells. It is ambitious without `VB`. What do you think `num` value should be for a use like `var program = new Program()`? Did you *optionally* want `num` to be `10` or is it default constructor where `num` is *field initialized* to be `0`??? – Sinatr Feb 20 '14 at 10:31
  • @Sinatr, this is a replication of a situation that I am facing. I wrote it that way so that I can differentiate the output and identify which constructor was getting called in C#. – Brij Feb 20 '14 at 10:37
  • 1
    It sounds like the VB compiler is doing you a favour to me. – Jodrell Feb 20 '14 at 10:53
  • @Jodrell, fully agree, we should have it in C# as well :) – Brij Feb 20 '14 at 10:56

2 Answers2

8

The problem is with the definitions of your constructors in the Program class

Because the argument to the second is optional, then both are candidates when calling using New Program(). This creates the ambiguity.

Instead, define your constructors using this sort of pattern:

public Program()
    : this(10)
{
}

public Program(int num)
{
    n = num;
}

or just the single constructor:

public Program(int num = 10)
{
    n = num;
}

(Personally I prefer the first of these).

Jon Egerton
  • 40,401
  • 11
  • 97
  • 129
  • @Jon_Egerton the change in constructor will sort the issue, but can we call the specific constructor without making any changes in the C# `Program` class ? Also, the ambiguity doesn't occur in C#, but occurs in VB.NET. Also in VB.NET it occurs in .NET 4.0 and not .NET 4.5 – Brij Feb 20 '14 at 10:35
  • Frankly, not sure - I have seem ambiguities slip through before, or start erroring after a while. However look at it another way. When you call "New Program()" what are you expecting for `n`? - 0 or 10? They're not just ambiguous at the code level, but at the "notional" level too. – Jon Egerton Feb 20 '14 at 10:59
  • When you say .Net 4, was that in VS2010 or VS2012/13? – Jon Egerton Feb 20 '14 at 11:05
  • 1
    See [Damien's answer](http://stackoverflow.com/a/21906563/592111). In C# it would have been handled for all these versions. For VB its a recent addition. Still a rubbish construct though - you'll never get the default of 10! – Jon Egerton Feb 20 '14 at 11:38
0

The best way would be to change the implementation of the constructor as also @JonEgerton wrote. If this is not possible, you could try the following - not really beautiful - workarounds:

  • If you know the inner implementation of the Program class, you can simply call the constructor with the int-Parameter with the value that the parameterless constructor assigns, in your sample Dim p As New Program(0). This implies that you need to be careful regarding later changes in the implementation of the constructors of the Program class as they will not be reflected in your implementation. For instance, if the implementors of the Program class change the value that is assigned in the parameterless constructor, your solution will still assign a value of 0.
  • As C# seems to handle the creation differently, you can also add a C# class (e.g. in a C# class library) that creates the instance of program for you and returns it to your code. Though this maybe means to add a class library to your solution for this sole purpose and therefore is not really a beautiful approach, later changes in the implementation of the Program class will be reflected in your program also.
Community
  • 1
  • 1
Markus
  • 20,838
  • 4
  • 31
  • 55