【问题标题】:Change CSharp code at compile time based on Assembly being used根据正在使用的程序集在编译时更改 CSharp 代码
【发布时间】:2012-10-28 14:48:17
【问题描述】:

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.targetsAssemblySearchPaths 属性的评论是:

<!--
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 常量?

【问题讨论】:

    标签: c# msbuild msbuild-4.0


    【解决方案1】:

    这就是我最终要做的。解析 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>
    

    【讨论】:

      猜你喜欢
      • 2014-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-09
      • 2014-05-03
      相关资源
      最近更新 更多