[CSHARP-280] Compiler error: ambiguous call between IEnumerable<MongoDB.Bson.BsonValue> and IEnumerable<object> in BsonArray Created: 25/Jul/11 Updated: 02/Apr/15 Resolved: 27/Jul/11 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | None |
| Affects Version/s: | 1.1 |
| Fix Version/s: | 1.2 |
| Type: | Bug | Priority: | Major - P3 |
| Reporter: | Roman Kuzmin | Assignee: | Robert Stam |
| Resolution: | Done | Votes: | 0 |
| Labels: | driver | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Backwards Compatibility: | Major Change |
| Description |
|
*) Build environment: *) Steps to reproduce: void TestCompilerError() // all 3 calls cannot compile .. and compile. Compilation fails with an error (3 similar errors): The call is ambiguous between the following methods or properties: 'MongoDB.Bson.BsonArray.Create(System.Collections.Generic.IEnumerable<MongoDB.Bson.BsonValue>)' and 'MongoDB.Bson.BsonArray.Create(System.Collections.Generic.IEnumerable<object>)' *) Possible solution: I tried to remove these 3 methods from the latest sources. The test code is compiled successfully. |
| Comments |
| Comment by Robert Stam [ 27/Jul/11 ] |
|
Rarely backward breaking at the source code level, but client code will have to be recompiled to pick up the new matching overloads in some cases. Note: there appear to be some similar ambiguities between IDictionary and IDictionary<string, object> but I will leave those for a separate JIRA ticket. |
| Comment by Roman Kuzmin [ 27/Jul/11 ] |
|
I am glad that you come to the same conclusion about replacing IEnumerable<object> in parameters with non-generic IEnumerable. As for the return values, yes, I prefer IEnumerable<object>, too, and this does not make any issues (as far as I know and can tell, neither in C# nor in PowerShell). |
| Comment by Robert Stam [ 27/Jul/11 ] |
|
The reason the call is ambiguous when .NET 3.5 is targeted is that in the absence of covariance there is no implicit conversion between IEnumerable<BsonValue> and IEnumerable<object>, so to the compiler both overloads are equally applicable and therefore ambiguous. In .NET 4 with the introduction of covariance there IS an implicit conversion from IEnumerable<BsonValue> to IEnumerable<object> but not the other way around, and that is enough to make the compiler decide that the overload with the more specific parameter type (i.e. IEnumerable<BsonValue>) is better and therefore when .NET 4 is targeted there no longer is any ambiguity. Furthermore, I agree with your analysis that wherever IEnumerable<object> is used (at least as an input parameter) we can use IEnumerable instead. I think for return values we can still stick to IEnumerable<object> where appropriate. |
| Comment by Roman Kuzmin [ 25/Jul/11 ] |
|
I propose the following (just like in https://jira.mongodb.org/browse/CSHARP-276). Replace API methods dealing with IEnumerable<object> with non-generic methods dealing with IEnumerable (perhaps not only in BsonArray). Reasons: 1) As we can see, non-generic methods open doors for PowerShell code; I think that in 3.5 methods X(IEnumerable<object>) should be avoided. They are not different by nature than X(IEnumerable) but they cannot be called with IEnumerable references. In contrast, non-generic methods can be called with IEnumerable<object>. Thus, API with non-generics gets more cases working fine in 3.5. As for the reasons of differences between 3.5 and 4.0., I am not sure. Compiler was changed, indeed. E.g. Covariance and Contravariance in Generics: |
| Comment by Robert Stam [ 25/Jul/11 ] |
|
At first I thought this issue was introduced by the implementation of Here's a short sample program that illustrates the issue without using the C# driver at all: namespace TestAmbiguousEnumerable { public static class Program { private static void F(IEnumerable<object> values) { private static void F(IEnumerable<C> values) { // commenting out this overload makes no difference This program compiles cleanly when targeting .NET 4 but gives the same compiler error when targeting .NET 3.5: Error 1 The call is ambiguous between the following methods or properties: 'TestAmbiguousEnumerable.Program.F(System.Collections.Generic.IEnumerable<object>)' and 'TestAmbiguousEnumerable.Program.F(System.Collections.Generic.IEnumerable<TestAmbiguousEnumerable.C>)' c:\users\robert stam\documents\visual studio 2010\Projects\TestAmbiguousEnumerable\Program.cs 14 13 TestAmbiguousEnumerable Only the class name has changed. I'm going to research this simplified case first. Anyone reading this see why this works with one version of .NET and not another? |
| Comment by Robert Stam [ 25/Jul/11 ] |
|
OK. I can reproduce it now. The key to reproducing is: "Target platform: .NET 3.5". My test program was targeted at .NET 4.0, in which case it does compile and run correctly. |
| Comment by Robert Stam [ 25/Jul/11 ] |
|
I am unable to reproduce. The following code compiles for me: var values = new BsonValue[] { }; var array1 = BsonArray.Create(values); var array2 = new BsonArray(values); var array3 = new BsonArray(); and produces the following output: [] Full source at: |