| File: TaskHostParameters.cs | Web Access |
| Project: src\msbuild\src\Framework\Microsoft.Build.Framework.csproj (Microsoft.Build.Framework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; namespace Microsoft.Build.Framework { /// <summary> /// A readonly struct that represents task host parameters used to determine which host process to launch. /// </summary> public readonly struct TaskHostParameters : IEquatable<TaskHostParameters> { /// <summary> /// A static empty instance to avoid allocations when default parameters are needed. /// </summary> public static readonly TaskHostParameters Empty = new(); private readonly string? _runtime; private readonly string? _architecture; private readonly string? _dotnetHostPath; private readonly string? _msBuildAssemblyPath; private readonly bool? _taskHostFactoryExplicitlyRequested; /// <summary> /// Initializes a new instance of the TaskHostParameters struct with the specified parameters. /// </summary> /// <param name="runtime">The target runtime identifier (e.g., "net8.0", "net472").</param> /// <param name="architecture">The target architecture (e.g., "x64", "x86", "arm64").</param> /// <param name="dotnetHostPath">The path to the dotnet host executable.</param> /// <param name="msBuildAssemblyPath">The path to the MSBuild assembly.</param> /// <param name="taskHostFactoryExplicitlyRequested">Defines if Task Host Factory was explicitly requested.</param> internal TaskHostParameters( string? runtime = null, string? architecture = null, string? dotnetHostPath = null, string? msBuildAssemblyPath = null, bool? taskHostFactoryExplicitlyRequested = null) { _runtime = runtime; _architecture = architecture; _dotnetHostPath = dotnetHostPath; _msBuildAssemblyPath = msBuildAssemblyPath; _taskHostFactoryExplicitlyRequested = taskHostFactoryExplicitlyRequested; } /// <summary> /// Gets the target runtime identifier (e.g., "net8.0", "net472"). /// </summary> /// <value>The runtime identifier, or null if not specified.</value> public string? Runtime => _runtime; /// <summary> /// Gets the target architecture (e.g., "x64", "x86", "arm64"). /// </summary> /// <value>The architecture identifier, or an empty string if not specified.</value> public string? Architecture => _architecture; /// <summary> /// Gets the path to the dotnet host executable. /// </summary> /// <value>The dotnet host path, or null if not specified.</value> public string? DotnetHostPath => _dotnetHostPath; /// <summary> /// Gets the path to the MSBuild assembly or executable. It can be either path to MSBuild.dll or to app host (MSBuild.exe). /// </summary> /// <value>The MSBuild assembly or executable path, or null if not specified.</value> public string? MSBuildAssemblyPath => _msBuildAssemblyPath; /// <summary> /// Gets if Task Host Factory was requested explicitly (by specifying TaskHost="TaskHostFactory" in UsingTask element). /// </summary> public bool? TaskHostFactoryExplicitlyRequested => _taskHostFactoryExplicitlyRequested; public override bool Equals(object? obj) => obj is TaskHostParameters other && Equals(other); public bool Equals(TaskHostParameters other) => StringComparer.OrdinalIgnoreCase.Equals(Runtime ?? string.Empty, other.Runtime ?? string.Empty) && StringComparer.OrdinalIgnoreCase.Equals(Architecture ?? string.Empty, other.Architecture ?? string.Empty) && TaskHostFactoryExplicitlyRequested == other.TaskHostFactoryExplicitlyRequested; public override int GetHashCode() { // Manual hash code implementation for compatibility with .NET Framework 4.7.2 var comparer = StringComparer.OrdinalIgnoreCase; unchecked { int hash = 17; hash = hash * 31 + comparer.GetHashCode(Runtime ?? string.Empty); hash = hash * 31 + comparer.GetHashCode(Architecture ?? string.Empty); hash = hash * 31 + (TaskHostFactoryExplicitlyRequested?.GetHashCode() ?? 0); return hash; } } /// <summary> /// Gets a value indicating whether returns true if parameters were unset. /// </summary> internal bool IsEmpty => Equals(Empty); /// <summary> /// Merges two TaskHostParameters instances, with the second parameter values taking precedence when both are specified. /// </summary> /// <param name="baseParameters">The base parameters.</param> /// <param name="overrideParameters">The override parameters that take precedence.</param> /// <returns>A new TaskHostParameters with merged values.</returns> internal static TaskHostParameters MergeTaskHostParameters(TaskHostParameters baseParameters, TaskHostParameters overrideParameters) { // If both are empty, return empty if (baseParameters.IsEmpty && overrideParameters.IsEmpty) { return Empty; } // If override is empty, return base if (overrideParameters.IsEmpty) { return baseParameters; } // If base is empty, return override if (baseParameters.IsEmpty) { return overrideParameters; } // Merge: override values take precedence, fall back to base values return new TaskHostParameters( runtime: overrideParameters.Runtime ?? baseParameters.Runtime, architecture: overrideParameters.Architecture ?? baseParameters.Architecture, dotnetHostPath: overrideParameters.DotnetHostPath ?? baseParameters.DotnetHostPath, msBuildAssemblyPath: overrideParameters.MSBuildAssemblyPath ?? baseParameters.MSBuildAssemblyPath, taskHostFactoryExplicitlyRequested: overrideParameters.TaskHostFactoryExplicitlyRequested ?? baseParameters.TaskHostFactoryExplicitlyRequested); } /// <summary> /// Creates a new instance of <see cref="TaskHostParameters"/> with the specified value for the /// <see cref="TaskHostFactoryExplicitlyRequested"/> property. /// </summary> internal TaskHostParameters WithTaskHostFactoryExplicitlyRequested(bool taskHostFactoryExplicitlyRequested) { if (_taskHostFactoryExplicitlyRequested == taskHostFactoryExplicitlyRequested) { return this; } return new TaskHostParameters( runtime: _runtime, architecture: _architecture, dotnetHostPath: _dotnetHostPath, msBuildAssemblyPath: _msBuildAssemblyPath, taskHostFactoryExplicitlyRequested: taskHostFactoryExplicitlyRequested); } /// <summary> /// The method was added to sustain compatibility with ITaskFactory2 factoryIdentityParameters parameters dictionary. /// </summary> internal Dictionary<string, string> ToDictionary() => new(3, StringComparer.OrdinalIgnoreCase) { { nameof(Runtime), Runtime ?? string.Empty }, { nameof(Architecture), Architecture ?? string.Empty }, { nameof(TaskHostFactoryExplicitlyRequested), TaskHostFactoryExplicitlyRequested?.ToString() ?? string.Empty }, }; } }