File: TaskHostParameters.cs
Web Access
Project: ..\..\..\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.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
    {
        /// <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.
        /// </summary>
        /// <value>The MSBuild assembly 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;
 
        /// <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>
        /// The method was added to sustain compatibility with ITaskFactory2 factoryIdentityParameters parameters dictionary.
        /// </summary>
        internal Dictionary<string, string> ToDictionary() => new(3)
        {
            { nameof(Runtime), Runtime ?? string.Empty },
            { nameof(Architecture), Architecture ?? string.Empty },
            { nameof(TaskHostFactoryExplicitlyRequested), TaskHostFactoryExplicitlyRequested?.ToString() ?? string.Empty },
        };
    }
}