Code that Builds in Visual Studio Won't Build

2019-05-31 04:10发布

问题:

I have two extension methods defined in a C# class. When I compile code that uses these extension methods in Visual Studio 2015, they compile correctly. When I run the same code on an on-premises Team Foundation Build Server, using MSBuild 2015 with /p:VisualStudioVersion=14.0, the code will not compile. What additional steps to do I need to take to configure the build server so that the code will compile?

These are the relevant method signatures

    public static IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector) where TInner : class;
    public static IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector) where TInner : class

This is the compile error on the build server:

I have two extension methods defined in a C# class. When I compile code that uses these extension methods in Visual Studio 2015, they compile correctly. When I run the same code on an on-premises Team Foundation Build Server, using MSBuild 2015 with /p:VisualStudioVersion=14.0, the code will not compile. What additional steps to do I need to take to configure the build server so that the code will compile?

These are the relevant method signatures

public static IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector)
    where TInner : class;
public static IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner?, TResult> resultSelector)
    where TInner : struct;

Based on the compiler error in the build server, it appears that the build process is accepting the "where TInner : struct" version of the method as a suitable overload even though TInner is a reference type, whereas Visual Studio on my development machine does not consider these methods ambiguous. This is the compile error on the build server:

The call is ambiguous between the following methods or properties:
'Extensions.LeftOuterJoin<AnonymousType#1,ReferenceType,AnonymousType#2,AnonymousType#3>(System.Collections.Generic.IEnumerable<AnonymousType#1>, System.Collections.Generic.IEnumerable<ReferenceType>, System.Func<AnonymousType#1,AnonymousType#2>, System.Func<ReferenceType,AnonymousType#2>, System.Func<AnonymousType#1,ReferenceType,AnonymousType#3>)'
and
'Extensions.LeftOuterJoin<AnonymousType#1,ReferenceType,AnonymousType#2,AnonymousType#4>(System.Collections.Generic.IEnumerable<AnonymousType#1>, System.Collections.Generic.IEnumerable<ReferenceType>, System.Func<AnonymousType#1,AnonymousType#2>, System.Func<ReferenceType,AnonymousType#2>, System.Func<AnonymousType#1,ReferenceType?,AnonymousType#4>)'

回答1:

If you are using TFS2015, you must make sure the build environment on your build machine be the same as your local develop machine. You should install VS2015 on your build machine.

If you are using TFS2013 or TFS2012 , this /p:VisualStudioVersion=14.0 argument doesn't work. You need to customize the tfs build process template to set ToolPath of the Run MSBuild for Project to target to MSBuild14; and set ToolVersion to "14.0". Check this BuildActivity ignores ToolsVersion for deatils.



回答2:

I know this is an old post, but just to extend a little bit on the answer, if you are using the TFS2015, you have two options to compile the code, one with the VisualStudio Build Task and the other with the MSBuild task, I suggest to go with the first one. Sometimes to target the MSBuild14 you have also two options

1- Targeting the MSBuild14 directly as @Patrick-MSFT said 2 - Instead of 1, you can include a Nuget dependency on the project named: Microsoft.Net.Compilers, the version 2.0.1 at the time of this answer is the right version to get the latest version of the C# compiler running as part of your build. Take a look also at my answer here: https://stackoverflow.com/a/42931980/819153

But most of the people don't like to update all projects on the same solution to target that nuget package. Instead of doing that, you need to have installed on the server the latest version of Microsoft Tools 2015 that you can download it from here https://www.microsoft.com/en-us/download/details.aspx?id=48159

Now in my experience, you need to take a deep look, you agents have capabilities, once you create an agent, it discovers the capabilities of your machine, it knows which are the version of the MSBuild you have installed, and in some cases, people install the MSBuild after they have the agents running. My advice, stop the agents and recreate them again after the installation of the MSBuild. The safest way to avoid problems on the TFS Server was installing the Visual Studio 2015 there, after redoing my agents everything run perfectly with the latest version of the MSBuild and also with the latest version of the Visual Studio. Installing Microsoft Tools 2015 is not giving you the latest version of the Visual Studio folder on the TFS. So you can install it, or instead of that create the MSBuild task and pass all the parameters you need

Hope this helps