我不清楚WriteCodeFragment任務的用途是什麼(https://msdn.microsoft.com/en-us/library/microsoft.build.tasks.writecodefragment.aspx)。谷歌似乎開啓了文檔,我看到的一個例子不是確定性的。MSBuild WriteCodeFragment任務
有人可以澄清嗎?謝謝。
我不清楚WriteCodeFragment任務的用途是什麼(https://msdn.microsoft.com/en-us/library/microsoft.build.tasks.writecodefragment.aspx)。谷歌似乎開啓了文檔,我看到的一個例子不是確定性的。MSBuild WriteCodeFragment任務
有人可以澄清嗎?謝謝。
它看起來只適用於使用屬性填充源代碼文件(您選擇的語言)(閱讀:將構建信息嵌入到項目中)。
這是任務的源代碼:()
https://github.com/Microsoft/msbuild/blob/master/src/XMakeTasks/WriteCodeFragment.cs
具體GenerateCode參考方法。 ,它的主要列舉看起來是屬性特定的類型(讀:聲明和非功能性):
/// <summary>
/// Generates the code into a string.
/// If it fails, logs an error and returns null.
/// If no meaningful code is generated, returns empty string.
/// Returns the default language extension as an out parameter.
/// </summary>
[SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.IO.StringWriter.#ctor(System.Text.StringBuilder)", Justification = "Reads fine to me")]
private string GenerateCode(out string extension)
{
extension = null;
bool haveGeneratedContent = false;
CodeDomProvider provider;
try
{
provider = CodeDomProvider.CreateProvider(Language);
}
catch (ConfigurationException ex)
{
Log.LogErrorWithCodeFromResources("WriteCodeFragment.CouldNotCreateProvider", Language, ex.Message);
return null;
}
catch (SecurityException ex)
{
Log.LogErrorWithCodeFromResources("WriteCodeFragment.CouldNotCreateProvider", Language, ex.Message);
return null;
}
extension = provider.FileExtension;
CodeCompileUnit unit = new CodeCompileUnit();
CodeNamespace globalNamespace = new CodeNamespace();
unit.Namespaces.Add(globalNamespace);
// Declare authorship. Unfortunately CodeDOM puts this comment after the attributes.
string comment = ResourceUtilities.FormatResourceString("WriteCodeFragment.Comment");
globalNamespace.Comments.Add(new CodeCommentStatement(comment));
if (AssemblyAttributes == null)
{
return String.Empty;
}
// For convenience, bring in the namespaces, where many assembly attributes lie
globalNamespace.Imports.Add(new CodeNamespaceImport("System"));
globalNamespace.Imports.Add(new CodeNamespaceImport("System.Reflection"));
foreach (ITaskItem attributeItem in AssemblyAttributes)
{
CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(new CodeTypeReference(attributeItem.ItemSpec));
// Some attributes only allow positional constructor arguments, or the user may just prefer them.
// To set those, use metadata names like "_Parameter1", "_Parameter2" etc.
// If a parameter index is skipped, it's an error.
IDictionary customMetadata = attributeItem.CloneCustomMetadata();
List<CodeAttributeArgument> orderedParameters = new List<CodeAttributeArgument>(new CodeAttributeArgument[customMetadata.Count + 1] /* max possible slots needed */);
List<CodeAttributeArgument> namedParameters = new List<CodeAttributeArgument>();
foreach (DictionaryEntry entry in customMetadata)
{
string name = (string)entry.Key;
string value = (string)entry.Value;
if (name.StartsWith("_Parameter", StringComparison.OrdinalIgnoreCase))
{
int index;
if (!Int32.TryParse(name.Substring("_Parameter".Length), out index))
{
Log.LogErrorWithCodeFromResources("General.InvalidValue", name, "WriteCodeFragment");
return null;
}
if (index > orderedParameters.Count || index < 1)
{
Log.LogErrorWithCodeFromResources("WriteCodeFragment.SkippedNumberedParameter", index);
return null;
}
// "_Parameter01" and "_Parameter1" would overwrite each other
orderedParameters[index - 1] = new CodeAttributeArgument(String.Empty, new CodePrimitiveExpression(value));
}
else
{
namedParameters.Add(new CodeAttributeArgument(name, new CodePrimitiveExpression(value)));
}
}
bool encounteredNull = false;
for (int i = 0; i < orderedParameters.Count; i++)
{
if (orderedParameters[i] == null)
{
// All subsequent args should be null, else a slot was missed
encounteredNull = true;
continue;
}
if (encounteredNull)
{
Log.LogErrorWithCodeFromResources("WriteCodeFragment.SkippedNumberedParameter", i + 1 /* back to 1 based */);
return null;
}
attribute.Arguments.Add(orderedParameters[i]);
}
foreach (CodeAttributeArgument namedParameter in namedParameters)
{
attribute.Arguments.Add(namedParameter);
}
unit.AssemblyCustomAttributes.Add(attribute);
haveGeneratedContent = true;
}
StringBuilder generatedCode = new StringBuilder();
using (StringWriter writer = new StringWriter(generatedCode, CultureInfo.CurrentCulture))
{
provider.GenerateCodeFromCompileUnit(unit, writer, new CodeGeneratorOptions());
}
string code = generatedCode.ToString();
// If we just generated infrastructure, don't bother returning anything
// as there's no point writing the file
return haveGeneratedContent ? code : String.Empty;
}
這只是另一個例子,我發現是這樣的:
(Using WriteCodeFragment MSBuild Task)
<Target Name="BeforeBuild">
<ItemGroup>
<AssemblyAttributes Include="AssemblyVersion">
<_Parameter1>123.132.123.123</_Parameter1>
</AssemblyAttributes>
</ItemGroup>
<WriteCodeFragment Language="C#" OutputFile="BuildVersion.cs" AssemblyAttributes="@(AssemblyAttributes)" />
</Target>
堵此成實際構建呈現:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: AssemblyVersion("123.132.123.123")]
// Generated by the MSBuild WriteCodeFragment class.
我想知道如何防止它做這個任務。 –
實測這裏參考的https:/ /github.com/Microsoft/msbuild/blob/c1459f5cbd36f2c33eafc8f4ff087f6ee84c3640/src/XMakeTasks/Microsoft.Common.CurrentVersion.targets#L3030,不知道它做了什麼,雖然 – stijn
@stijn在我做了一些更多的調查後看到答案。 –