基于常量的 Visual Studio 条件项目引用

20

为了用户授权,我只想为每个用户包含特定的模块。因此,我进行了如下的条件编译配置。

<DefineConstants>TRACE;DEBUG;SAMPLECONSTANT1</DefineConstants>

并且像这样编辑了项目文件:

<ProjectReference Include="..\Solution1.Modules.Module1\Solution1.Modules.Module1.csproj" Condition="$(DefineConstants.Contains('SAMPLECONSTANT1'))">
  <Project>{4E378BD0-4FF8-4160-9331-1ECBFD2B6F30}</Project>
  <Name>Solution1.Modules.Module1</Name>
</ProjectReference>
针对这种情况,如果DefineConstants包含SAMPLECONSTANT1,我想要添加对项目Module1的引用;但无论我在DefineConstants中放什么,解决方案始终会加载Module1项目。 我做错了什么吗? 更新:实际上我的代码是正确的。请参见J0e3gan的答案。 Visual Studio UI不反映项目References文件夹中的条件引用。因此,在任何给定的配置或平台选择下,所有引用都是可见的。 另一方面,编译器和IntelliSense知道有条件的引用,并在构建过程中以正确的设置进行错误通知和视觉反馈。

1
请您能否详细阐述一下,因为目前还不够清晰。 - cuongle
嗨,Cuong Le,我刚刚更新了我的问题。对于这个问题,如果DefineConstants包含SAMPLECONSTANT1,我想要添加对项目Module1的引用,但是无论我在DefineConstants中放置什么,解决方案总是加载Module1项目。 - chinh nguyen van
1
我的想法是在运行时加载模块会更好,而不是编译时。你可以使用反射或MEF来实现这一点。 - cuongle
我根据我的理解稍微调整了一下,因为我认为你真正想要的是对项目引用进行条件设置,而不是将项目包含在解决方案中:我找到了一种适合我的方法,希望你也能发现它对你有用。 - J0e3gan
3个回答

30

我怀疑问题在于您将项目的引用与是否在解决方案中包含 Module1联系起来了。

当然,将项目包含在解决方案中(因此使用解决方案加载它)和项目引用解决方案中的另一个项目是两件不同的事情。

更新:

如果您真正想要条件化项目引用,Joe Wrobel撰写了一篇相关博客文章,应该会有所帮助。关键是将包含ProjectReferenceItemGroupChoose元素包裹起来,例如:

<Choose>
  <When Condition="$(DefineConstants.Contains('SAMPLECONSTANT1'))">
    <ItemGroup>
      <ProjectReference Include="..\Solution1.Modules.Module1\Solution1.Modules.Module1.csproj">
        <Project>{4E378BD0-4FF8-4160-9331-1ECBFD2B6F30}</Project>
        <Name>Solution1.Modules.Module1</Name>
      </ProjectReference>
      <!-- other ProjectReference elements -->
    </ItemGroup>
  </When>
  <Otherwise>
    <ItemGroup>
      <!-- other ProjectReference elements -->
    </ItemGroup>
  </Otherwise>
</Choose>

根据我今晚的测试,这种方式非常适用于将项目引用(s)的条件限制在如SAMPLECONSTANT1 这样的常量是否被定义。但需要注意的是,无论所使用的条件常量是否被定义,受到限制的项目引用不会显示在解决方案资源管理器中(本来应该出现在)引用项目的“引用”文件夹下。

为了验证条件的生效,我进行了构建:SAMPLECONSTANT1被定义时,使用在Module1中定义的类,该引用项目成功构建——如预期的那样;而当SAMPLECONSTANT1未被定义时,该引用项目构建失败,因为无法解析Module1中定义的类——同样符合预期。


2
如果我引用一个DLL而不是一个项目,就像这样工作得很好:<Reference Include="Solution1.Modules.Module1, Version=1.0.0.0, Culture=neutral, processorArchitecture=x86"> </Reference>因此我不知道为什么ProjectReference不起作用。 - chinh nguyen van
3
你的答案是正确的,我测试过了并且它起作用了。我只在项目的“References”文件夹中进行了检查,仍然看到了该项目,这就是为什么我认为我的代码没有起作用,真傻。对于任何对此感兴趣的人,你也可以使用我的代码,它更简单,不需要使用 ChooseWhen 标签 :) - chinh nguyen van
@chinhnguyenvan: 你说得对。多么讽刺啊:我不得不通过“选择”方法来发现引用与构建的区别 - 然后发现(在你的评论的提示下)它也对你的方法有所不同!一个MSDN MSBuild thread稍微讨论了这个问题。现在我想知道Eugene Zakhareyev在他的回复中是否真的是指“你肯定可以调整引用使其有条件;关键是它在VS中将是[ ]不可见的,并且不能通过UI进行编辑…”。 - J0e3gan
2
@chinhnguyenvan:有趣的是:我找到了你所说的有条件引用始终可见于“引用”下的区别,以及我的经验是有条件的引用始终不可见。使用ProjectReference元素的Condition属性,有条件的项目引用始终显示在“引用”下 - 就像你描述的那样;而使用我概述的Choose-When方法,项目引用始终不可见于“引用”下。奇怪。:) 顺便说一句,我使用Visual Studio 2010 Professional SP1测试了所有内容,以获得完整的上下文。 - J0e3gan
1
你的判断是正确的,我们两个人的代码都可以运行,只是在“引用”文件夹中看不到。非常感谢你的帮助。 - chinh nguyen van

1

对我来说,被接受的答案并没有起作用。然而,我并不意味着它是错误的。对我有用的是这个:

<Import Project="..\MnM.GWS.Chip2\MnM.GWS.Chip1.projitems" Label="Shared" Condition="$(DefineConstants.Contains('Chip1'))" />
<Import Project="..\MnM.GWS.Chip2\MnM.GWS.Chip2.projitems" Label="Shared" Condition="$(DefineConstants.Contains('Chip2'))" />

在更改常量时,我没有遇到任何错误。


0

如果您想使用DEBUG常量,请确保在项目属性中启用它(属性 > 构建 > 定义DEBUG常量)。

基于已接受答案的示例:

  <Choose>
    <When Condition="$(DefineConstants.Contains('DEBUG'))">
      <ItemGroup>
        <ProjectReference Include="..\..\..\..\..\MyLocalProjectPath.csproj" />
      </ItemGroup>
    </When>
    <Otherwise>
      <ItemGroup>
        <PackageReference Include="MyNugetPackage" Version="2.1.4" />
      </ItemGroup>
    </Otherwise>
  </Choose>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接