Ambiguous function/constructor call in C#
Asked Answered
R

6

7

The following code causes a compiler error, as it is ambiguous call but the problem if we use object instead of ArrayList no error happens and the string version works fine; Do you have an explanation for that?

class A
{
    public A(string x)
    {
        Console.WriteLine("string");
    }
    public A(ArrayList x)
    {
        Console.WriteLine("ArrayList");
    }

}
    static void Main(string[] args)
        {
            A o = new A(null);
        }
Reece answered 19/5, 2010 at 12:25 Comment(3)
I'm sure someone will post a better explanation than I could, but needless to say, you should probably avoid this pattern and implement a default constructor. Oh wait, I said it...Eb
What version of .NET do you use? Because if you use 2.0 or over, you could use an IList<T> or whatever other collection that best fits your situation? Implementing a default constructor might also help.Townsley
@Will Marcouiller: .Net 3.5 but I wonder about the behavior itself this is an exampleReece
S
16

The reason your code works fine if you change the constructor that takes an ArrayList to take an object is that the C# compiler will pick the most specific type applicable. In the case of string/object, string actually derives from object and is therefore "more specific" and will be inferred by the compiler. With string versus ArrayList, it's apples and oranges: either can be null, but neither is more "specific" than the other.

Suricate answered 19/5, 2010 at 12:32 Comment(4)
+1 beat me to the explanation. Your answer is the only one that answers the actual question.Imaret
Line of the day : it's apples and oranges: either can be null, but neither is more "specific" than the other. :)Jeffrey
@TheMachineCharmer: What, you've never eaten a null apple? They're delicious.Suricate
NO. There were only 4 null apples. And they were all consumed by by Adam,Isaac Newton,Steve Jobs and you! (chronologically) :) lolJeffrey
A
4

I could be wrong, but I think the reason it works when you change ArrayList to object is because string inherits from object and it decides to use the more specific string version. When it's string and ArrayList it doesn't know which one to use.

Acclivity answered 19/5, 2010 at 12:32 Comment(0)
A
3

null could represent either a string, or an ArrayList. There's no information there is to which version of the method (in this case a constructor) you meant.

You can force it to use a specific one by casting:

static void Main(string[] args)
    {
        A o = new A((string)null);
    }

...or alternately implementing a constructor that behaves as you want (that takes no parameter)

Ashwin answered 19/5, 2010 at 12:27 Comment(2)
An object could be null too, but the OP indicated that changing ArrayList to object resolves the issue; so this isn't the whole picture. The real issue is that in this case, neither type will "win" in the eyes of the compiler because one does not inherit from the other. In the case of string vs. object, string wins out because it derives from object and is therefore more specific.Suricate
What about using object, you did not answer meReece
A
2

you can tackle this situation by using default keyword like, and the code will be:

A o = new A(default(ArrayList)); 

Or

A o = new A(default(string)); 
Apiary answered 21/3, 2014 at 10:38 Comment(0)
G
1
  1. Of course it's ambiguous: null could be either a string or an ArrayList. You'll need to qualify it, like (string) null.
  2. Did you know that ArrayList is deprecated? You should use one of the generic collection types instead
Geniculate answered 19/5, 2010 at 12:29 Comment(5)
For the ArrayList, it depends on the version of the Framework he uses, I guess. But good point for the null ambiguity.Townsley
@Will: if he's still using .NET 1.1, I'd tell him that .NET 1.1 has been deprecated.Geniculate
Hehehe... Right! =) But sometimes one has to deal with administrative decisions. If it's not broken, don't fix it! But yet, I get your point anyway. =)Townsley
I putted ArrayList as an example I am using .Net 3.5Reece
ArrayList is a class you should no longer use. The direct replacement is List<object>.Geniculate
J
1

ArrayList and string are both nullable types. That confuses compiler.

If you have two constructors say one that takes nullable type e.g. ArrayList and other that takes non-nullable type e.g. int. The code will compile and choose the constructor with nullable type.

But if you have more that one constructor that takes nullable type then like @Dan Tao said it's apples and oranges: either can be null, but neither is more "specific" than the other.

for example:

class A
{
    public A(int x)
    {
        Console.WriteLine("string");
    }
    public A(ArrayList x)
    {
        Console.WriteLine("ArrayList");
    }

}

This code compiles but if you change public A(int x)t to public A(int? x) it will NOT.

Jeffrey answered 19/5, 2010 at 12:47 Comment(3)
It's not really to do with them being nullable\reference types, but rather that there is no 'best' option to choose between string and ArrayList. If you had a function with an overload taking a Stream, and one taking a MemoryStream and called it with null then the compiler would be able to resolve it.Abiotic
@Abiotic Thanks! But could you please explain how compiler resolves it in that case?Jeffrey
This post from Eric Lippert explains overload resolution better than me - #2856523.Abiotic

© 2022 - 2024 — McMap. All rights reserved.