|
// 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;
using System.Collections.Generic;
#nullable disable
namespace Microsoft.Build.Logging.StructuredLogger
{
/// <summary>
/// This class encapsulates functionality for a collection of properties (name value pairs) in a
/// hierarchical way. (e.g. if the parameter is defined and identical in the parent, it is not
/// stored in this instance).
/// </summary>
internal sealed class PropertyBag
{
/// <summary>
/// The parent instance.
/// </summary>
private readonly PropertyBag _parent;
/// <summary>
/// The properties defined at this level.
/// </summary>
private readonly Dictionary<string, string> _properties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Initializes a new instance of the <see cref="PropertyBag"/> class.
/// </summary>
/// <param name="properties">The initial properties to set.</param>
/// <param name="parent">The parent <see cref="PropertyBag"/> instance.</param>
public PropertyBag(IEnumerable<KeyValuePair<string, string>> properties, PropertyBag parent = null)
: this(parent)
{
AddProperties(properties);
}
/// <summary>
/// Initializes a new instance of the <see cref="PropertyBag"/> class.
/// </summary>
/// <param name="parent">The parent <see cref="PropertyBag"/>.</param>
public PropertyBag(PropertyBag parent = null)
{
_parent = parent;
}
/// <summary>
/// Gets the properties associated with this instance (without parent properties).
/// </summary>
/// <value>
/// The properties.
/// </value>
public IDictionary<string, string> Properties { get { return _properties; } }
/// <summary>
/// Adds properties to the collection.
/// </summary>
/// <param name="newProperties">The new properties.</param>
public void AddProperties(IEnumerable<KeyValuePair<string, string>> newProperties)
{
if (newProperties == null)
{
throw new ArgumentNullException(nameof(newProperties));
}
foreach (var property in newProperties)
{
AddProperty(property.Key, property.Value);
}
}
/// <summary>
/// Adds properties to the collection.
/// </summary>
/// <remarks>If the property is defined and identical in the parent, no action is taken.</remarks>
/// <param name="newProperties">The new properties.</param>
/// <exception cref="System.ArgumentException">newProperties</exception>
public void AddProperties(IEnumerable<DictionaryEntry> newProperties)
{
if (newProperties == null)
{
throw new ArgumentNullException(nameof(newProperties));
}
foreach (var property in newProperties)
{
AddProperty(property.Key.ToString(), property.Value.ToString());
}
}
/// <summary>
/// Add a single property to the collection.
/// </summary>
/// <remarks>If the property is defined and identical in the parent, no action is taken.</remarks>
/// <param name="key">The property key.</param>
/// <param name="value">The property value.</param>
public void AddProperty(string key, string value)
{
string currentValue;
if (_properties.TryGetValue(key, out currentValue))
{
// We've already seen the property here, update value if different
if (currentValue != value)
{
_properties[key] = value;
}
}
else if (_parent != null && _parent.TryGetValue(key, out currentValue))
{
// The parent has the property, only add if different
if (currentValue != value)
{
_properties.Add(key, value);
}
}
else
{
// No one has the property, just add it.
_properties.Add(key, value);
}
}
/// <summary>
/// Tries the get the value for the property in this scope.
/// </summary>
/// <param name="key">The property key.</param>
/// <param name="value">Out: The property value.</param>
/// <returns>True if the property was found and set, else false.</returns>
public bool TryGetValue(string key, out string value)
{
if (_properties.TryGetValue(key, out value))
{
return true;
}
return _parent?.TryGetValue(key, out value) == true;
}
}
}
|