根据正在使用的程序集在编译时更改CSharp代码

时间:2012-11-08 11:47:34

标签: c# msbuild msbuild-4.0

Test.csproj引用System.XML并指定TargetFrameworkVersion v4.0。 System.Xml.XmlReaderSettings获得DtdProcessing属性,同时弃用ProhibitDtd。 要求是从一个项目构建,支持两个程序集。

使用MSBuild 3.5(c:\ Windows \ Microsoft.NET \ Framework \ v3.5 \ MSBuild)构建它最终引用C:\ Windows \ Microsoft.NET \ Framework \ v2.0.50727 \ System.Xml.dll(运行时版本v2.0.50727,版本2.0.0.0)

使用MSBuild 4.0构建(c:\ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ MSBuild),它最终引用C:\ Program Files \ Reference Assemblies \ Microsoft \ Framework.NETFramework \ v4.0 \ System。 Xml.dll(运行时版本v4.0.30319,版本4.0.0.0)。

我尝试修复的方法是根据TargetFrameworkVersion在.csproj文件中定义一个常量。 但是,TargetFrameworkVersion并不指示将链接哪个程序集。

所以,这不起作用:

<PropertyGroup Condition=" '$(TargetFrameworkVersion)' != 'v2.0' And '$(TargetFrameworkVersion)' != 'v3.5' And '$(TargetFrameworkVersion)' != '' ">
  <DefineConstants Condition=" '$(DefineConstants)' != '' ">$(DefineConstants);</DefineConstants>
  <DefineConstants>$(DefineConstants)XMLDTDPROCESSING</DefineConstants>
</PropertyGroup>

使用此CSharp代码:

namespace TestVSMSBuild
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Xml.XmlReaderSettings readerSettings = new System.Xml.XmlReaderSettings();
#if XMLDTDPROCESSING
            readerSettings.DtdProcessing = System.Xml.DtdProcessing.Ignore;
#else // !XMLDTDPROCESSING
            readerSettings.ProhibitDtd = false;
#endif // XMLDTDPROCESSING
            System.Console.WriteLine("Reader: '{0}'", readerSettings);
        }
    }

阅读C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets AssemblySearchPaths属性的评论是:

<!--
The SearchPaths property is set to find assemblies in the following order:

    (1) Files from current project - indicated by {CandidateAssemblyFiles}
    (2) $(ReferencePath) - the reference path property, which comes from the .USER file.
    (3) The hintpath from the referenced item itself, indicated by {HintPathFromItem}.
    (4) The directory of MSBuild's "target" runtime from GetFrameworkPath.
        The "target" runtime folder is the folder of the runtime that MSBuild is a part of.
    (5) Registered assembly folders, indicated by {Registry:*,*,*}
    (6) Legacy registered assembly folders, indicated by {AssemblyFolders}
    (7) Look in the application's output folder (like bin\debug)
    (8) Resolve to the GAC.
    (9) Treat the reference's Include as if it were a real file name.
-->
<AssemblySearchPaths Condition=" '$(AssemblySearchPaths)' == '' ">
    {CandidateAssemblyFiles};
    $(ReferencePath);
    {HintPathFromItem};
    {TargetFrameworkDirectory};
    {Registry:$(FrameworkRegistryBase),$(TargetFrameworkVersion),$(AssemblyFoldersSuffix)$(AssemblyFoldersExConditions)};
    {AssemblyFolders};
    {GAC};
    {RawFileName};
    $(OutDir)
</AssemblySearchPaths>

我的猜测是这与GetFrameworkPaths有关,定义为:

<!--
============================================================
                                    GetFrameworkPaths

Get the paths for the .NET Framework installation directory, and the .NET Framework
SDK installation directory.

These paths are not used directly by this .targets file but are available for pre and
post build steps.
============================================================
-->
<PropertyGroup>
    <Framework35Dir>@(_TargetFramework35DirectoryItem)</Framework35Dir>
    <Framework30Dir>@(_TargetFramework30DirectoryItem)</Framework30Dir>
    <Framework20Dir>@(_TargetFramework20DirectoryItem)</Framework20Dir>
    <FrameworkDir>@(_TargetFramework20DirectoryItem)</FrameworkDir>

    <FrameworkSDKDir>@(_TargetFrameworkSDKDirectoryItem)</FrameworkSDKDir>
    <GetFrameworkPathsDependsOn></GetFrameworkPathsDependsOn>
</PropertyGroup>
<Target
    Name="GetFrameworkPaths"
    DependsOnTargets="$(GetFrameworkPathsDependsOn)">

    <!-- Get the paths to all of the target .NET framework directories. -->
    <GetFrameworkPath>
        <Output Condition=" '$(TargetFrameworkVersion)' == 'v3.5' "                                                                                  TaskParameter="FrameworkVersion35Path"  ItemName="_CombinedTargetFrameworkDirectoriesItem" />
        <Output Condition=" '$(TargetFrameworkVersion)' == 'v3.0' or '$(TargetFrameworkVersion)' == 'v3.5' "                                         TaskParameter="FrameworkVersion30Path"  ItemName="_CombinedTargetFrameworkDirectoriesItem" />
        <Output Condition=" '$(TargetFrameworkVersion)' == 'v2.0' or '$(TargetFrameworkVersion)' == 'v3.0' or '$(TargetFrameworkVersion)' == 'v3.5'" TaskParameter="FrameworkVersion20Path"  ItemName="_CombinedTargetFrameworkDirectoriesItem" />
        <Output TaskParameter="FrameworkVersion35Path"  ItemName="_TargetFramework35DirectoryItem" />
        <Output TaskParameter="FrameworkVersion30Path"  ItemName="_TargetFramework30DirectoryItem" />
        <Output TaskParameter="FrameworkVersion20Path"  ItemName="_TargetFramework20DirectoryItem" />
    </GetFrameworkPath>

    <PropertyGroup>
        <TargetFrameworkDirectory>@(_CombinedTargetFrameworkDirectoriesItem)</TargetFrameworkDirectory>
    </PropertyGroup>

    <!-- Get the path to the target .NET framework SDK directory. -->
    <GetFrameworkSdkPath>
        <Output TaskParameter="FrameworkSdkVersion35Path" PropertyName="TargetFrameworkSDKDirectory"/>
        <Output TaskParameter="FrameworkSdkVersion35Path" ItemName="_TargetFrameworkSDKDirectoryItem"/>
    </GetFrameworkSdkPath>

</Target>

那么,是否有更简单的方法可以根据所使用的System.XML程序集更改CSharp代码? 如果这种方法是正确的,应该用 来定义我的XMLDTDPROCESSING常量?

1 个答案:

答案 0 :(得分:0)

这是我最终做的事情。解析System.XML程序集,然后专门检查版本2.0.0.0。

请注意,假设System.XML程序集路径以System.XML结尾。似乎没有办法将ReferencePath绑定回相应的Reference。

<!-- System.XML.XmlReaderSettings changed after version 2.0.0.0.
     Define a constant to recognised that.
 -->
<Target Name="SetupXMLDtdProcessing">
  <GetAssemblyIdentity AssemblyFiles="%(ReferencePath.Identity)"
                       Condition=" '%(ReferencePath.Filename)' == 'System.XML' "
  >
    <Output TaskParameter="Assemblies" ItemName="_SystemXMLAssemblyIdentityItem" />
  </GetAssemblyIdentity>

  <PropertyGroup>
    <_SystemXMLAssemblyIdentity>%(_SystemXMLAssemblyIdentityItem.Identity)</_SystemXMLAssemblyIdentity>
  </PropertyGroup>

  <PropertyGroup Condition=" '$(_SystemXMLAssemblyIdentity)' != 'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
                           "
  >
    <DefineConstants Condition=" '$(DefineConstants)' != '' ">$(DefineConstants);</DefineConstants>
    <DefineConstants>$(DefineConstants)XMLDTDPROCESSING</DefineConstants>
  </PropertyGroup>
</Target>

<PropertyGroup>
  <CompileDependsOn>
    SetupXMLDtdProcessing;
    $(CompileDependsOn)
  </CompileDependsOn>
</PropertyGroup>