Resolving extension methods/LINQ ambiguity - c#

I'm writing an add-in for ReSharper 4. For this, I needed to reference several of ReSharper's assemblies. One of the assemblies (JetBrains.Platform.ReSharper.Util.dll) contains a System.Linq namespace, with a subset of extension methods already provided by System.Core.
When I edit the code, it creates an ambiguity between those extensions, so that I cannot use OrderBy, for instance. How could I solve this? I would like to use the core LINQ extensions, and not the ones from ReSharper.
I get the following error when trying to compile:
The call is ambiguous between the
following methods or properties:
'System.Linq.Enumerable.OrderBy<string,int>(System.Collections.Generic.IEnumerable<string>,
System.Func<string,int>)' and
'System.Linq.Enumerable.OrderBy<string,int>(System.Collections.Generic.IEnumerable<string>,
System.Func<string,int>)'
EDIT: I tried the suggestion below, unfortunately without luck. In the meanwhile, I "solved" the problem by removing references to System.Core. This way I could use the extensions provided by ReSharper DLL files.
I uploaded a sample program where I just imported the ReSharper DLL files I needed. I changed the alias of System.Core to SystemCore, added the extern alias directive, but it still didn't work. If I missed something, please let me know.
P.S. The references are to ReSharper v4.1 DLL files installed in the default directroy in "C:\Program Files\JetBrains\ReSharper\v4.1\...".

This is probably one of those rare cases where it makes sense to use an extern alias.
In the properties page for the reference to System.Core (i.e. under References, select System.Core, right-click and select "Properties"), change the "Aliases" value to "global,SystemCore" (or just "SystemCore" if it's blank to start with).
Then in your code, write:
extern alias SystemCore;
using SystemCore::System.Linq;
That will make all the relevant types etc in System.Core.dll's System.Linq namespace available. The name "SystemCore" here is arbitrary - you could call it "DotNet" or something else if that would make it clearer for you.

This isn't really an answer, but may provide an easier way for others to reproduce the issue (from the command-line - you could do it with two projects in Visual Studio if you want).
1) Create BadLinq.cs and build it as BadLinq.dll:
using System.Collections.Generic;
namespace System.Linq
{
public static class Enumerable
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source,
Func<T,bool> predicate)
{
return null;
}
}
}
2) Create Test.cs:
extern alias SystemCore;
using System;
using SystemCore::System.Linq;
static class Test
{
static void Main()
{
var names = new[] { "Larry", "Curly", "Moe" };
var result = names.Where(x => x.Length > 1);
}
}
3) Compile Test.cs specifying the extern alias:
csc Test.cs /r:BadLinq.dll /r:SystemCore=System.Core.dll
This fails with:
Test.cs(11,28): error CS1061:
'System.Array' does not contain a
definition for 'Where' and no
extension method 'Where' accepting a first argument of type
'System.Array' could be found
(are you missing a using directive or an assembly reference?)
If you change it to not try to use an extension method (i.e. Enumerable.Where) it works fine with the extern alias.
I think this may be a compiler bug. I've emailed a private mailing list which the C# team reads - I'll update this answer or add a new one when I hear back.

This is no longer an issue, since I am able to use the LINQ extensions, as provided by ReSharper DLL files, even while targeting .NET 3.0.
Mr. Skeet was right again! I am able to use full LINQ syntax, while targeting .NET 3.0 in the project's properties and not referencing System.Core!

In order for ReSharper to be as compatible as possible with the variety of solutions it is used with, it is built against .NET 2.0. LINQ, etc. came in in C# 3.0, so they are not available in that version of the Framework. So, JetBrains added in their own version.
The solution is to build your addin against .NET 2.0 as well.

I had the ambiguous reference problem using System.ComponentModel. Visual Studio was complaining that a DLL file exists in both v2 and v4. I was able to resolve it by removing the reference to the System DLL file and readding it.

One solution would be to move all your code out to a partial class that uses the ReSharper code. In there, you'd import only the ReSharper namespace and not System.Core.
In the rest of the partial class, you'd import all the other namespaces you need, including System.Core, but not the ReSharper namespace.

I had the same problem, even with extern alias, and I raised it as a compiler bug on Connect. The workaround for the time being is to forgo the extension method syntax.
The bug is fixed for Visual Studio 2010.

It is really a compiler error.
I had the same problem, and I solved it just by cleaning and rebuilding the project. After that the problem disappeared.

I had a similar situation. After two hours struggling I realized I had duplicate namespace names in my libraries. If you are using file Dynamic.cs published by Microsoft, the only thing you need to do is rename the current namespace to something else, and it will be fixed.
//Copyright (C) Microsoft Corporation. All rights reserved.
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace System.Linq.Dynamic <- for example to Linq.Dynamic
{

I found this same sort of ambiguity when use PagedList in MVC (.Net 4.5, MVC 5). I found that if I took the object for the argument that was ambiguous and cast it explicitly first, the problem was resolved. To if the ambiguity was between a method that takes System.Linq.Enumerable and one that takes System.Collections.Generic.IEnumerable as the parameter in question, and the source is of type System.Collections.Generic.IEnumerable, I don't use the extension method on it. I cast it.In this example, my repository method returns a List:
searchRequest.CaseSearchResults = csr.SelectMatchingCases(searchRequest);
var results = searchRequest.CaseSearchResults.AsEnumerable<CaseSearchResult>();
int pageNum = (int)(ViewBag.PageNum ?? 1);
var pageResults =results.ToPagedList<CaseSearchResult>(pageNum, 5);
Calling the extension method on searchRequest.CaseSearchResults caused the ambiguity error; explicitly casting to results and then calling the extension on that worked.

Related

GroupCollection.First builds in netcoreapp but not in netstandard

I am getting errors building netcoreapp code in netstandard I cannot resolve.
The following code compiles in netcoreapp2.2:
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace TestNamespace
{
public class TestClass
{
public static Group Example(string str, string pattern) =>
Regex.Match(str, pattern).Groups.First();
}
}
But if I change it to netstandard2.0 then .First fails to compile with:
Class1.cs(10, 46): [CS1061] 'GroupCollection' does not contain a definition for 'First' and no accessible extension method 'First' accepting a first argument of type 'GroupCollection' could be found (are you missing a using directive or an assembly reference?)
However if I use "go to code" in Jetbrains Rider, the disassembly for GroupCollection resolves to System.Text.RegularExpressions, Version=4.2.1.0 which implements IList. I have manually added this assembly and System.Linq but the error persists.
Any idea what is happening? Any idea of a fix?
GroupCollection in later versions of .NET Core implements IList<Group>. IList<Group> is sufficient for LINQ extension methods (like First) to work.
GroupCollection in .NET Framework (or earlier versions of .NET Core) does not implement that interface (it implements the older (non-generic) interfaces only). Thus, you can't use First without casting it.
If you do decide to Cast, then the same code will work for everything (.NET Core / Standard / Framework).

The type or namespace name" 'BigInteger' could not be found

Seriously bummed by this. Wanted to give BigInteger's a spin, but:
The type or namespace name" 'BigInteger' could not be found ...
I know how to add assembly references and such, but there is NO System.Numerics present at all - or then I'm completely and utterly blind.
How to fix?
Using Microsoft Visual Studio Community 2015.
In project properties:
Target framework: .NET Framework 4.5.2
System.Numerics is present (and selected) in Frameworks:
But still, even something this simple:
using System;
using System.Numerics;
namespace CCHfT
{
class Program
{
static void Main(string[] args)
{
BigInteger b = 0;
Console.WriteLine($"...{b}");
}
}
}
...fails with the error message mentioned earlier.
It appears that you're not looking in the right place. From your screenshot you can see that you're missing a ton of System. assemblies, and the ones that are shown all have older versions. This looks like what you would see under the COM -> Type Libraries section of the References Manager window.
Try selecting Assemblies -> Framework. You should see something like "Targeting: .NET Framework 4.5.2" at the top, and System.Numerics 4.0.0.0 in the list:
Also, ensure that after clicking 'OK' on the References window, that the reference appears under your Project Properties:
Figured it out ... facedesk ...
Was looking at WRONG piece of a multi-project solution. No wonder fiddling with references didn't work when I was fooling around with wrong sub-project's assembly reference list...
Need more coffee... -.-

The same type is defined in two assemblies

I have a VSTO-addin, which uses CustomTaskPanes. My code compiles and works fine, but problem comes from code analizers, like Resharper and Code contracts for .net.
This code provokes error messages from both analizers:
CustomTaskPane taskPane = CustomTaskPanes.Add(new UserControl(), "Title");
taskPane.DockPosition = MsoCTPDockPosition.msoCTPDockPositionFloating;
Cannot convert source type 'Microsoft.Office.Core.MsoCTPDockPosition [office, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c]' to target type 'Microsoft.Office.Core.MsoCTPDockPosition [Microsoft.Office.Tools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]'
That is weird, because public type Microsoft.Office.Core.MsoCTPDockPosition exists only in office.dll. Anyway, I tried to resolve it using aliases and named Microsoft.Office.Tools.Common as Tools_Common:
extern alias Tools_Common;
using System;
using System.Windows.Forms;
using Microsoft.Office.Core;
using Tools_Common::Microsoft.Office.Tools;
using CustomTaskPane = Tools_Common::Microsoft.Office.Tools.CustomTaskPane;
But it didn't help at all. What is the cause of the message? How can I solve it (especially for code contracts)?
Also, I found another strange artifact - Resharper's autocomplete shows MsoCTPDockPosition like it exists in Microsoft.Office.Tools.Common.dll, but then I try to do autocomplete, it uses office.dll version:
You should use Microsoft Office 15.0 Object Library from the COM tab in VS instead of that office.dll
So, I tried a few different ways and found solutions. I found that if I change the Office.dll assembly to another version from
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Visual Studio Tools for Office\PIA\Office15\Office.dll, 15.0.4420.1017
to
C:\Windows\assembly\GAC_MSIL\office, 15.0.4787.1001
then Resharper works fine. But Code Contracts still give me the same error. So I fooled it using the dynamic word
((dynamic) taskPane).DockPosition = MsoCTPDockPosition.msoCTPDockPositionFloating;
I'm not really happy about using dynamic. But Code Contracts are pretty important to me, so I can tolerate a little dirtiness for that.
If someone can explain, why Resharper started to work well after I changed version or find better, cleaner solution for Code Contracts - I will reaccept the answer.
Edit:
((dynamic) taskPane).DockPosition shows TargetExceptions and says that the property doesn't exist in the object. So I changed it to use reflection
typeof(CustomTaskPane)
.InvokeMember("DockPosition", BindingFlags.SetProperty, null, taskPane, new object[] { MsoCTPDockPosition.msoCTPDockPositionFloating }, null);

Type or namespace 'MSBuild' does not exist in namespace 'Microsoft.CodeAnalysis' despite being able to navigate to definition

I'm trying out Roslyn for the first time and I'm writing a small piece of code to read through a project, classes and class members.
I'm using the MSBuildWorkspace class to create the Roslyn workspace (MSBuildWorkspace.Create()). Below is a small part of the code I've written
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.MSBuild; //Some problem in this line? Read on.
...
...
var workspace = MSBuildWorkspace.Create();
Solution solutionToAnalyze =
workspace.OpenSolutionAsync(pathToSolution).Result;
IEnumerable<Project> projectsToAnalyze =
solutionToAnalyze.Projects;
...
...
When I do a "Go to Definition" on MSBuildWorkspace class, I'm able to navigate to the class's definition and I can clearly see it's namespace to be Microsoft.CodeAnalysis.MSBuild (See image below).
But despite this, I keep getting the error message, "The type or namespace MSBuild doesn't exist in the namespace 'Microsoft.CodeAnalysis' at the using statement that I've highlighted with the comment". I just can't seem to get the reason behind this error. Am I missing anything?
I found the answer thanks to the link provided by #CZabransky.
https://stackoverflow.com/a/23621818/2377928
Basically I was overlooking the below warning that I was getting. (One more reason why one SHOULDN'T overlook warnings! o_O)
My project was targeting Framework version 4.5 and so this assembly was not building as it was built against the v4.5.2 version. I had to target the framework version to 4.6 and the solution built successfully.
Hope this helps!
You need to add a reference to Microsoft.CodeAnalysis.Workspaces.MSBuild.dll which comes from the Nuget package Microsoft.CodeAnalysis.Workspaces.MSBuild.

Microsoft.Bcl package using CallerMemberName fails to build within Teamcity

I have taken over a project that is targeting .net4.
One of the projects within the solution is using System.Runtime.CompilerServices.CallerMemberNameAttribute from the System.Runtime.dll that is installed when you are using the Microsoft BCL Portability Pack.
I have checked and the project is currently using version 1.1.3.
When the solution is build on local dev machines, everything compliles with no problems.
I am now trying to get the solution built in teamcity, but when TeamCity attempts to compile the solution I am getting this error.
error CS0246: The type or namespace name 'CallerMemberName' could not be found (are you missing a using directive or an assembly reference?)
error CS0433: The type 'System.Runtime.CompilerServices.CallerMemberNameAttribute' exists in both 'c:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll' and 'c:\apps\teamcity\buildAgent\work\bb8aacaa9fabeac8\packages\Microsoft.Bcl.1.1.3\lib\net40\System.Runtime.dll'
I have read Jon Skeets answer to this question: Using CallerMemberName attribute in a portable library But I am already using the BCL library.
After spending some time on this, I found another question answered by Jon Skeet that resolved this issue.
When must we use extern alias keyword in C#?
Within my project, after getting the links to the Package, for each dll I had to change the name of the alias. ie from global to newglobal
Then in the classes that where using the CallerMemberName, had to do the following
At the top of the page, above the using statements
extern alias newglobal;
And then when referencing CallerMemberName, enter the code as
[newglobal::System.Runtime.CompilerServices.CallerMemberName]
This allows the code to be successfully built on teamcity where .net 4.5 has been installed.

Categories