diff --git a/src/BenchmarkDotNet/Jobs/Argument.cs b/src/BenchmarkDotNet/Jobs/Argument.cs
index c86c83906a..6ec416c8e7 100644
--- a/src/BenchmarkDotNet/Jobs/Argument.cs
+++ b/src/BenchmarkDotNet/Jobs/Argument.cs
@@ -45,8 +45,34 @@ public MonoArgument(string value) : base(value)
/// example: new MsBuildArgument("/p:MyCustomSetting=123")
///
[PublicAPI]
+
+ ///
+ /// A specialized MSBuild argument that sets a property using a quoted, semicolon-separated list of values.
+ ///
+ public class MsBuildProperty : MsBuildArgument
+ {
+ public MsBuildProperty(string key, params string[] values)
+ : base($"/p:{key}=\"{string.Join(";", values)}")
+ {
+ }
+
+
+ }
public class MsBuildArgument : Argument
{
public MsBuildArgument(string value) : base(value) { }
+
+ public MsBuildArgument(string key, params string[] values)
+ : base($"/p:{key}={EscapeAndJoin(values)}") { }
+
+ private static string EscapeAndJoin(string[] values)
+ {
+ return string.Join("%3b", values.Select(EscapeSpecialChars));
+ }
+
+ private static string EscapeSpecialChars(string input)
+ {
+ return input.Replace(";", "%3B");
+ }
}
}
\ No newline at end of file
diff --git a/tests/BenchmarkDotNet.IntegrationTests.ManualRunning/MsBuildArgumentTests.cs b/tests/BenchmarkDotNet.IntegrationTests.ManualRunning/MsBuildArgumentTests.cs
index f4619040cc..22c346ec2d 100644
--- a/tests/BenchmarkDotNet.IntegrationTests.ManualRunning/MsBuildArgumentTests.cs
+++ b/tests/BenchmarkDotNet.IntegrationTests.ManualRunning/MsBuildArgumentTests.cs
@@ -24,6 +24,13 @@ public void ProcessIsBuiltWithCustomProperty(bool setCustomProperty)
CanExecute(config);
}
+ [Fact]
+
+ public void MsBuildProperty_ShouldWrapMultipleValuesInQuotes()
+ {
+ var arg = new MsBuildProperty("DefineConstants", "FOO", "BAR");
+ Assert.Equal("/p:DefineConstants=\"FOO;BAR\"", arg.TextRepresentation);
+ }
[Fact]
public void MultipleProcessesAreBuiltWithCorrectProperties()
{