using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace ObjectDataUtils
{
/// <summary>
/// Allows to extend any .NET objects with dynamic dictionary storage,
/// which will be collected by GC with the associated object
/// Latest code is here: https://gist.github.com/pmunin/b369f1e2555653970fc9
/// </summary>
public static class ObjectDataExtensions
{
static readonly ConditionalWeakTable<object, ConcurrentDictionary<string, object>> dataByObject = new ConditionalWeakTable<object, ConcurrentDictionary<string, object>>();
/// <summary>
/// Retrieves the data dictionary attached to the object. Dictionary is deallocated by GC when associated object is.
/// </summary>
/// <param name="target">extended object</param>
/// <param name="createIfNotExist">create extension dictionary if it does not exist</param>
/// <returns></returns>
public static ConcurrentDictionary<string, object> Data(this object target, bool createIfNotExist = true)
{
var data = createIfNotExist ? dataByObject.GetOrCreateValue(target) : dataByObject.GetValue(target);
return data;
}
/// <summary>
/// Try get value from weak table and return default if it does not exist
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="conditionalWeakTable"></param>
/// <param name="key"></param>
/// <returns></returns>
static TValue GetValue<TKey, TValue>(this ConditionalWeakTable<TKey, TValue> conditionalWeakTable,
TKey key, TValue defaultValue = default(TValue)) where TKey : class where TValue : class
{
TValue resValue = null;
if (conditionalWeakTable.TryGetValue(key, out resValue))
return resValue;
return defaultValue;
}
/// <summary>
/// Retrieves value by key attached to the object and null if value does not exist
/// </summary>
/// <param name="target"></param>
/// <param name="key"></param>
/// <returns></returns>
public static object Data(this object target, string key)
{
var objectData = target.Data(false);
if (objectData == null) return null;
object result = null;
objectData.TryGetValue(key, out result);
return result;
}
/// <summary>
/// Sets add key value pair to the object's dynamic data
/// </summary>
/// <param name="target"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static object Data(this object target, string key, object value)
{
var objectData = target.Data();
objectData[key] = value;
return value;
}
}
}