| File: VariableCollection.cs | Web Access |
| Project: src\sdk\src\TemplateEngine\Microsoft.TemplateEngine.Core\Microsoft.TemplateEngine.Core.csproj (Microsoft.TemplateEngine.Core) |
// 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; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Core.Contracts; namespace Microsoft.TemplateEngine.Core { public class VariableCollection : IVariableCollection, IMonitoredVariableCollection { private static readonly IEnumerable<string> NoKeys = []; private readonly IDictionary<string, object> _values; private IVariableCollection? _parent; public VariableCollection() : this(null) { } public VariableCollection(VariableCollection? parent) : this(parent, new Dictionary<string, object>()) { } public VariableCollection(IVariableCollection? parent, IDictionary<string, object> values) { if (values != null) { if (values.Values.Any(o => o is null)) { throw new ArgumentException($"The {nameof(values)} should not contain null.", nameof(values)); } } _parent = parent; _values = values ?? new Dictionary<string, object>(); if (_parent is not null and IMonitoredVariableCollection monitored) { monitored.KeysChanged += RelayKeysChanged; } } public event KeysChangedEventHander? KeysChanged; public event ValueReadEventHander? ValueRead; public int Count => Keys.Count; public bool IsReadOnly => false; public ICollection<string> Keys => _values.Keys.Union(_parent?.Keys ?? NoKeys).ToList(); public IVariableCollection? Parent { get => _parent; set { _parent = value; OnKeysChanged(); } } public ICollection<object> Values => Keys.Select(x => this[x]).ToList(); public object this[string key] { get { if (_values.TryGetValue(key, out object result)) { ValueReadEventArgs args = new(key, result); OnValueRead(args); return result; } if (_parent?.TryGetValue(key, out result) ?? false) { return result; } throw new KeyNotFoundException($"No entry was found for key: {key}"); } set { bool changing = !_values.ContainsKey(key); _values[key] = value ?? throw new ArgumentNullException(nameof(value)); if (changing) { OnKeysChanged(); } } } public static VariableCollection Root() => Root(new Dictionary<string, object>()); public static VariableCollection Root(IDictionary<string, object> values) => new(null, values); public void Add(KeyValuePair<string, object> item) { if (_parent?.ContainsKey(item.Key) ?? false) { throw new InvalidOperationException("Key already added"); } if (item.Value is null) { throw new ArgumentException($"The value of key-value pair {nameof(item)} should not be null.", nameof(item)); } _values.Add(item); OnKeysChanged(); } public void Add(string key, object value) { if (_parent?.ContainsKey(key) ?? false) { throw new InvalidOperationException("Key already added"); } if (value is null) { throw new ArgumentNullException(nameof(value)); } _values.Add(key, value); OnKeysChanged(); } public void Clear() { if (_values.Count > 0) { _values.Clear(); OnKeysChanged(); } } public bool Contains(KeyValuePair<string, object> item) { return _values.Contains(item) || (_parent?.Contains(item) ?? false); } public bool ContainsKey(string key) => _values.ContainsKey(key) || (_parent?.ContainsKey(key) ?? false); public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) { int index = arrayIndex; foreach (string key in Keys) { if (index >= array.Length) { break; } array[index++] = new KeyValuePair<string, object>(key, this[key]); } } public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => Keys.Select(x => new KeyValuePair<string, object>(x, this[x])).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_values).GetEnumerator(); public bool Remove(KeyValuePair<string, object> item) => Remove(item.Key); public bool Remove(string key) { if (_values.Remove(key)) { if (!(_parent?.ContainsKey(key) ?? false)) { OnKeysChanged(); } return true; } return false; } public bool TryGetValue(string key, out object value) { if (_values.TryGetValue(key, out value)) { OnValueRead(key, value); return true; } return _parent?.TryGetValue(key, out value) ?? false; } private void OnKeysChanged() { KeysChanged?.Invoke(this, KeysChangedEventArgs.Default); } private void OnValueRead(string key, object value) { OnValueRead(new ValueReadEventArgs(key, value)); } private void OnValueRead(IValueReadEventArgs args) { ValueRead?.Invoke(this, args); } private void RelayKeysChanged(object sender, IKeysChangedEventArgs args) { OnKeysChanged(); } } }