using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#pragma warning disable CS8603 // Possible null reference return.
#pragma warning disable CS8601 // Possible null reference assignment.
namespace EasyDevCore.Common.Wrapper
{
///
/// Defines common methods for INameValueList and IReadOnlyNameValueList.
///
public interface INameValueListBase
{
///
/// Returns the first Value of the given Name if one exists, otherwise null or default value.
///
TValue FirstOrDefault(string name);
///
/// Gets the first Value of the given Name, if one exists.
///
/// true if any item of the given name is found, otherwise false.
bool TryGetFirst(string name, out TValue value);
///
/// Gets all Values of the given Name.
///
IEnumerable GetAll(string name);
///
/// True if any items with the given Name exist.
///
bool Contains(string name);
///
/// True if any item with the given Name and Value exists.
///
bool Contains(string name, TValue value);
}
///
/// Defines an ordered collection of Name/Value pairs where duplicate names are allowed but aren't typical.
///
public interface INameValueList : IList<(string Name, TValue Value)>, INameValueListBase
{
///
/// Adds a new Name/Value pair.
///
void Add(string name, TValue value);
///
/// Replaces the first occurrence of the given Name with the given Value and removes any others,
/// or adds a new Name/Value pair if none exist.
///
void AddOrReplace(string name, TValue value);
///
/// Removes all items of the given Name.
///
/// true if any item of the given name is found, otherwise false.
bool Remove(string name);
}
///
/// Defines a read-only ordered collection of Name/Value pairs where duplicate names are allowed but aren't typical.
///
public interface IReadOnlyNameValueList : IReadOnlyList<(string Name, TValue Value)>, INameValueListBase
{
}
///
/// An ordered collection of Name/Value pairs where duplicate names are allowed but aren't typical.
/// Useful for things where a dictionary would work great if not for those pesky edge cases (headers, cookies, etc).
///
public class NameValueList : List<(string Name, TValue Value)>, INameValueList, IReadOnlyNameValueList
{
private StringComparison _ComparisonType;
///
/// Instantiates a new empty NameValueList.
///
public NameValueList(StringComparison comparisonType)
{
_ComparisonType = comparisonType;
}
///
/// Instantiates a new NameValueList with the Name/Value pairs provided.
///
public NameValueList(IEnumerable<(string Name, TValue Value)> items, StringComparison comparisonType)
{
_ComparisonType = comparisonType;
AddRange(items);
}
///
public void Add(string name, TValue value) => Add((name, value));
///
public void AddOrReplace(string name, TValue value)
{
var i = 0;
var replaced = false;
while (i < this.Count)
{
if (!string.Equals(this[i].Name, name, _ComparisonType))
i++;
else if (replaced)
this.RemoveAt(i);
else
{
this[i] = (name, value);
replaced = true;
i++;
}
}
if (!replaced)
this.Add(name, value);
}
///
public bool Remove(string name) => RemoveAll(x => string.Equals(x.Name, name, _ComparisonType)) > 0;
///
public TValue FirstOrDefault(string name) => GetAll(name).FirstOrDefault();
///
public bool TryGetFirst(string name, out TValue value)
{
foreach (var v in GetAll(name))
{
value = v;
return true;
}
value = default;
return false;
}
///
public IEnumerable GetAll(string name) => this
.Where(x => string.Equals(x.Name, name, _ComparisonType))
.Select(x => x.Value);
///
public bool Contains(string name) => this.Any(x => string.Equals(x.Name, name, _ComparisonType));
///
public bool Contains(string name, TValue value) => Contains((name, value));
}
}