You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/Config/BaseConfiguration.cs

412 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using ZeroLevel.Services.Reflection;
using ZeroLevel.Services.Serialization;
namespace ZeroLevel.Services.Config
{
/// <summary>
/// Упрощенная конфигурация, без разделения параметров по секциям
/// </summary>
internal sealed class BaseConfiguration :
IConfiguration
{
#region Private members
/// <summary>
/// Указывает на заморозку конфигурации, все изменения запрещены
/// </summary>
private bool _freezed = false;
/// <summary>
/// Указывает на перманентную заморозку конфигурации, разморозка запрещена
/// </summary>
private bool _permanentFreezed = false;
private readonly object _freezeLock = new object();
/// <summary>
/// Список вида ключ-значение
/// </summary>
private readonly ConcurrentDictionary<string, IList<string>> _keyValues = new ConcurrentDictionary<string, IList<string>>();
/// <summary>
/// Пустой список
/// </summary>
private static readonly IEnumerable<string> EmptyValuesList = new List<string>(0);
private static string GetKey(string key)
{
if (string.IsNullOrWhiteSpace(key))
{
throw new ArgumentNullException("key");
}
return key.Trim().ToLower(CultureInfo.InvariantCulture);
}
#endregion
#region Properties
/// <summary>
/// Список значений по ключу
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Список значений</returns>
public IEnumerable<string> this[string key]
{
get
{
key = key.ToLower(CultureInfo.CurrentCulture);
IList<string> result;
if (_keyValues.TryGetValue(key, out result))
{
return result;
}
return EmptyValuesList;
}
}
/// <summary>
/// Список ключей
/// </summary>
public IEnumerable<string> Keys
{
get { return _keyValues.Keys; }
}
public bool Freezed
{
get
{
return _freezed;
}
}
#endregion
#region Public methods
#region Get
/// <summary>
/// Получение списка значение соотвествующих указанному ключу
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Список значений</returns>
public IEnumerable<string> Items(string key)
{
return this[key];
}
/// <summary>
/// Получение первого значения для указанного ключа
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Первое значение, или null если ключ есть, но нет значений, или KeyNotFoundException если нет ключа</returns>
public string First(string key)
{
IList<string> result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return result[0];
return null;
}
throw new KeyNotFoundException("Key not found: " + key);
}
public void DoWithFirst(string key, Action<string> action)
{
if (Contains(key))
{
action(First(key));
}
}
public void DoWithFirst<T>(string key, Action<T> action)
{
if (Contains(key))
{
action(First<T>(key));
}
}
/// <summary>
/// Получение первого значения для указанного ключа, с попыткой преобразования в указанный тип
/// </summary>
/// <typeparam name="T">Ожидаемый тип</typeparam>
/// <param name="key">Ключ</param>
/// <returns>Первое значение, или default(T) если ключ есть, но нет значений, или KeyNotFoundException если нет ключа</returns>
public T First<T>(string key)
{
IList<string> result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return (T)StringToTypeConverter.TryConvert(result[0], typeof(T));
return default(T);
}
throw new KeyNotFoundException("Parameter not found: " + key);
}
/// <summary>
/// Получение первого значения для указанного ключа, или значения по умолчанию
/// </summary>
/// <param name="key">Ключ</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Первое значение, или значение по умолчанию если нет значений или ключа</returns>
public string FirstOrDefault(string key, string defaultValue)
{
IList<string> result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return result[0];
}
return defaultValue;
}
/// <summary>
/// Получение первого значения для указанного ключа, или значения по умолчанию, с попыткой преобразования в указанный тип
/// </summary>
/// <typeparam name="T">Ожидаемый тип</typeparam>
/// <param name="key">Ключ</param>
/// <returns>Первое значение, или default(T) если нет значений или ключа</returns>
public T FirstOrDefault<T>(string key)
{
IList<string> result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return (T)StringToTypeConverter.TryConvert(result[0], typeof(T));
}
return default(T);
}
/// <summary>
/// Получение первого значения для указанного ключа, или значения по умолчанию, с попыткой преобразования в указанный тип
/// </summary>
/// <typeparam name="T">Ожидаемый тип</typeparam>
/// <param name="key">Ключ</param>
/// <param name="defaultValue">Значение по умолчанию</param>
/// <returns>Первое значение, или значение по умолчанию если нет значений или ключа</returns>
public T FirstOrDefault<T>(string key, T defaultValue)
{
IList<string> result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return (T)StringToTypeConverter.TryConvert(result[0], typeof(T));
}
return defaultValue;
}
/// <summary>
/// Проверка наличия ключа и непустого списка связанных с ним значений
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>true - если существует ключ и есть хотя бы одно значение</returns>
public bool Contains(string key)
{
key = GetKey(key);
return _keyValues.ContainsKey(key) && _keyValues[key].Count > 0;
}
/// <summary>
/// Проверка наличия одного из ключей
/// </summary>
public bool Contains(params string[] keys)
{
foreach (var key in keys)
if (Contains(key)) return true;
return false;
}
/// <summary>
/// Проверка наличия ключа и связанного с ним значения
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool ContainsValue(string key, string value)
{
IList<string> result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
return result.Contains(value);
}
return false;
}
/// <summary>
/// Количество значений связанных с указанным ключом
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Количество значений</returns>
public int Count(string key)
{
key = GetKey(key);
if (_keyValues.ContainsKey(key))
{
return _keyValues[key].Count;
}
return 0;
}
#endregion
/// <summary>
/// Добавление ключа и связанного с ним значения
/// </summary>
/// <param name="key">Ключ</param>
/// <param name="value">Значение</param>
public IConfiguration Append(string key, string value)
{
if (false == _freezed)
{
key = GetKey(key);
if (false == _keyValues.ContainsKey(key))
{
_keyValues.TryAdd(key, new List<string>());
}
_keyValues[key].Add(value?.Trim() ?? null);
}
return this;
}
/// <summary>
/// Задает значение в единственном числе,
/// существующее значение будет перезаписано
/// </summary>
public IConfiguration SetUnique(string key, string value)
{
if (false == _freezed)
{
key = GetKey(key);
if (false == _keyValues.ContainsKey(key))
{
_keyValues.TryAdd(key, new List<string>());
}
_keyValues[key].Clear();
_keyValues[key].Add(value?.Trim() ?? null);
}
return this;
}
/// <summary>
/// Очистка связанного с ключом списка значений
/// </summary>
/// <param name="key">Ключ</param>
public IConfiguration Clear(string key)
{
if (false == _freezed)
{
key = GetKey(key);
if (_keyValues.ContainsKey(key))
{
_keyValues[key].Clear();
}
}
return this;
}
/// <summary>
/// Очистка конфигурации
/// </summary>
public IConfiguration Clear()
{
if (false == _freezed)
{
_keyValues.Clear();
}
return this;
}
/// <summary>
/// Удаление ключа и связанных с ним значений
/// </summary>
/// <param name="key">Ключ</param>
public IConfiguration Remove(string key)
{
if (false == _freezed)
{
IList<string> removed;
_keyValues.TryRemove(GetKey(key), out removed);
}
return this;
}
public bool Freeze(bool permanent = false)
{
lock (_freezeLock)
{
if (false == _freezed)
{
_freezed = true;
_permanentFreezed = permanent;
return true;
}
else if (_permanentFreezed == false && permanent)
{
_permanentFreezed = true;
return true;
}
return false;
}
}
public bool Unfreeze()
{
lock (_freezeLock)
{
if (_freezed && _permanentFreezed == false)
{
_freezed = false;
return true;
}
return false;
}
}
#endregion
#region IEquatable
public bool Equals(IConfiguration other)
{
if (other == null)
{
return false;
}
if (this.Keys.NoOrderingEquals(other.Keys) == false)
{
return false;
}
foreach (var key in Keys)
{
if (this[key].NoOrderingEquals(other[key]) == false)
{
return false;
}
}
return true;
}
#endregion
#region Binary Serializable
public void Serialize(IBinaryWriter writer)
{
writer.WriteBoolean(this._freezed);
writer.WriteBoolean(this._permanentFreezed);
writer.WriteInt32(_keyValues.Count);
foreach (var pair in _keyValues)
{
writer.WriteString(pair.Key);
writer.WriteInt32(pair.Value.Count);
foreach (var value in pair.Value)
{
writer.WriteString(value);
}
}
}
public void Deserialize(IBinaryReader reader)
{
this._freezed = reader.ReadBoolean();
this._permanentFreezed = reader.ReadBoolean();
var count = reader.ReadInt32();
_keyValues.Clear();
for (int i = 0; i < count; i++)
{
var key = reader.ReadString();
var count_values = reader.ReadInt32();
var list_values = new List<string>();
for (var k = 0; k < count_values; k++)
{
list_values.Add(reader.ReadString());
}
_keyValues.TryAdd(key, list_values);
}
}
#endregion
}
}

Powered by TurnKey Linux.