写了一个超级吃内存的“疯狂数据库”。用空间换时间。
本集合可以拓展一下作为一个泛型List使用。适用于引索常量对象。
并发List(ConcurrentList)集合依赖于开源项目:
https://github.com/azborgonovo/SlimConcurrentCollections
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using SlimConcurrentCollections;
namespace Inspector_For_Test_Sieves.Model.Entities
{
/// <summary>
/// 专门用于存储偏向常量、字段类型独立不重复的数据,提供高效查询。
/// 偏向只增不减。(非线程安全)
/// </summary>
public class CrazyAddOnlyDatabase<T> : IEnumerable where T : class
{
public class ReadWriteMethod
{
public const string GetValueMethodName = "GetValue";
public const string SetValueMethodName = "SetValue";
public static readonly Type[] GetValueMethodParams = {typeof(object)};
public static readonly Type[] SetValueMethodParams = {typeof(object), typeof(object)};
public static readonly MethodInfo FieldInfoRead =
typeof(FieldInfo).GetMethod(GetValueMethodName, GetValueMethodParams);
public static readonly MethodInfo FieldInfoWrite =
typeof(FieldInfo).GetMethod(SetValueMethodName, SetValueMethodParams);
public static readonly MethodInfo PropertyInfoRead =
typeof(PropertyInfo).GetMethod(GetValueMethodName, GetValueMethodParams);
public static readonly MethodInfo PropertyInfoWrite =
typeof(PropertyInfo).GetMethod(SetValueMethodName, SetValueMethodParams);
protected object MethodProvider;
protected MethodInfo ReadMethod;
protected MethodInfo WriteMethod;
public object Read(object operationTarget)
{
return ReadMethod.Invoke(MethodProvider, new[] {operationTarget});
}
public object Write(object operationTarget, object inputValue)
{
return WriteMethod.Invoke(MethodProvider, new[] {operationTarget, inputValue});
}
public ReadWriteMethod(FieldInfo fieldInfo)
{
MethodProvider = fieldInfo;
ReadMethod = FieldInfoRead;
WriteMethod = FieldInfoWrite;
}
public ReadWriteMethod(PropertyInfo propertyInfo)
{
MethodProvider = propertyInfo;
ReadMethod = PropertyInfoRead;
WriteMethod = PropertyInfoWrite;
}
}
/// <summary>
/// 记录每一列的类型(有序)
/// </summary>
protected List<Type> MyColumnTypeList = new List<Type>();
/// <summary>
/// 记录每一列的反射类型(有序)
/// </summary>
protected List<MemberInfo> MemberInfoList = new List<MemberInfo>();
/// <summary>
/// 记录每一列的读写方法(有序)
/// </summary>
protected List<ReadWriteMethod> MethodInfoList = new List<ReadWriteMethod>();
/// <summary>
/// 记录每一列的类型 的 字段名称(有序)
/// </summary>
protected List<string> MyColumnNameList = new List<string>();
/// <summary>
/// 每一列的引索。以对象里的每一个字段的值作为 键,值 是 行下标。
/// </summary>
protected List<ConcurrentDictionary<object, List<int>>> RowIndexDatabase =
new List<ConcurrentDictionary<object, List<int>>>();
/// <summary>
/// 记录每一行的对象
/// </summary>
protected ConcurrentList<T> RowList = new ConcurrentList<T>();
// /// <summary>
// /// 记录主键列(不允许重复)
// /// </summary>
// protected Dictionary<string, int> PrimaryKeyColumn = new Dictionary<string, int>();
/// <summary>
/// 字段名称做主键,加速引索查询
/// </summary>
protected IDictionary<string, int> ColumnNameListCache = new Dictionary<string, int>();
/// <summary>
/// Type 字段做主键,加速引索查询。
/// (注意!这只会引索到同类型的其中一个!
/// 最好是在类型不重复的情况下使用)
/// </summary>
protected IDictionary<Type, int> ColumnTypeListCache = new Dictionary<Type, int>();
/// <summary>
/// C#泛型如果不是class类型则无法使用“as”关键词来无损拆箱。
/// 为了克服泛型支持性不佳而使用反射强行调用
/// </summary>
protected MethodInfo MethodInfoGetListByColumnWithClassType;
/// <summary>
/// 是否为字段值为 null 的 字段 添加引索
/// </summary>
public bool NoIndex4Null { get; set; }
public IReadOnlyList<Type> ColumnTypeList => MyColumnTypeList.AsReadOnly();
public IReadOnlyList<string> ColumnNameList => MyColumnNameList.AsReadOnly();
public System.Collections.ObjectModel.ReadOnlyDictionary<string, int> ColumnNameDictionary =>
new System.Collections.ObjectModel.ReadOnlyDictionary<string, int>(ColumnNameListCache);
public System.Collections.ObjectModel.ReadOnlyDictionary<Type, int> ColumnTypeDictionary =>
new System.Collections.ObjectModel.ReadOnlyDictionary<Type, int>(ColumnTypeListCache);
public CrazyAddOnlyDatabase() : this(false)
{
}
public CrazyAddOnlyDatabase(bool noIndex4Null) :
this(BindingFlags.Instance | BindingFlags.Public, noIndex4Null)
{
}
public CrazyAddOnlyDatabase(BindingFlags bindingAttr, bool noIndex4Null)
{
MethodInfoGetListByColumnWithClassType = this.GetType().GetMethod(
nameof(GetListByColumnWithClassType)
);
Type type = typeof(T);
PropertyInfo[] propertyInfos = type.GetProperties(bindingAttr);
FieldInfo[] fieldInfos = type.GetFields(bindingAttr);
NoIndex4Null = noIndex4Null;
int column = 0;
for (int j = 0; j < propertyInfos.Length; j++, column++)
{
PropertyInfo propertyInfo = propertyInfos[j];
MemberInfoList.Add(propertyInfo);
MethodInfoList.Add(new ReadWriteMethod(propertyInfo));
MyColumnTypeList.Add(propertyInfo.PropertyType);
MyColumnNameList.Add(propertyInfo.Name);
ColumnNameListCache[propertyInfo.Name] = column;
ColumnTypeListCache[propertyInfo.PropertyType] = column;
RowIndexDatabase.Add(new ConcurrentDictionary<object, List<int>>());
}
for (int j = 0; j < fieldInfos.Length; j++, column++)
{
FieldInfo fieldInfo = fieldInfos[j];
MemberInfoList.Add(fieldInfo);
MethodInfoList.Add(new ReadWriteMethod(fieldInfo));
MyColumnTypeList.Add(fieldInfo.FieldType);
MyColumnNameList.Add(fieldInfo.Name);
ColumnNameListCache[fieldInfo.Name] = column;
ColumnTypeListCache[fieldInfo.FieldType] = column;
RowIndexDatabase.Add(new ConcurrentDictionary<object, List<int>>());
}
}
public int GetColumnIndexByFieldName(string fieldName) => ColumnNameListCache[fieldName];
public int GetColumnIndexByFieldType(Type type) => ColumnTypeListCache[type];
/// <summary>
/// 按 字段类型 和 确切值 查询行记录。
/// (注意!这只会引索到同类型的其中一个!
/// 最好是在类型不重复的情况下使用)
/// </summary>
public List<T> QueryRow(Type fieldType, object value)
{
List<T> result = new List<T>();
if (!ColumnTypeListCache.ContainsKey(fieldType))
return result;
int column = ColumnTypeListCache[fieldType];
ConcurrentDictionary<object, List<int>> db = RowIndexDatabase[column];
db.TryGetValue(value, out List<int> rows);
if (rows != null)
{
for (int i = 0; i < rows.Capacity; i++)
{
result.Add(RowList[rows[i]]);
}
}
return result;
}
/// <summary>
/// 按 字段名称 和 确切值 查询行记录。
/// </summary>
public List<T> QueryRow(string fieldName, object value)
{
List<T> result = new List<T>();
if (!ColumnNameListCache.ContainsKey(fieldName))
return result;
int column = ColumnNameListCache[fieldName];
ConcurrentDictionary<object, List<int>> db = RowIndexDatabase[column];
db.TryGetValue(value, out List<int> rows);
if (rows != null)
{
for (int i = 0; i < rows.Capacity; i++)
{
result.Add(RowList[rows[i]]);
}
}
return result;
}
/// <summary>
/// 直接按 确切值(及其类型) 查询行记录。
/// (注意!这只会引索到同类型的其中一个!
/// 最好是在类型不重复的情况下使用)
/// </summary>
public List<T> QueryRow(object value)
{
return QueryRow(value.GetType(), value);
}
/// <summary>
/// 直接按 确切值(及其类型) 查询第一个匹配的行记录。
/// (注意!这只会引索到同类型的其中一个!
/// 最好是在类型不重复的情况下使用)
/// </summary>
public T QueryFirstRow(object value)
{
T result = null;
Type fieldType = value.GetType();
if (ColumnTypeListCache.ContainsKey(fieldType))
{
// 定位 到 列
int column = ColumnTypeListCache[fieldType];
// 检索同值的 行 的 下标
ConcurrentDictionary<object, List<int>> db = RowIndexDatabase[column];
db.TryGetValue(value, out List<int> rows);
if (rows != null)
{
//添加检索到的行
result = RowList[rows[0]];
}
}
return result;
}
public ArrayList GetListByFieldName(string fieldName) =>
GetListByColumnIndex(GetColumnIndexByFieldName(fieldName));
public ArrayList GetListByFieldType(Type fieldType) =>
GetListByColumnIndex(GetColumnIndexByFieldType(fieldType));
public ArrayList GetListByColumnIndex(int column)
{
ReadWriteMethod rw = MethodInfoList[column];
ArrayList result = new ArrayList();
for (int i = 0; i < RowList.Count; i++)
{
result.Add(rw.Read(RowList[i]));
}
return result;
}
public List<T2> GetListByColumnWithForcedType<T2>(int column)
{
ReadWriteMethod rw = MethodInfoList[column];
List<T2> result = new List<T2>();
for (int i = 0; i < RowList.Count; i++)
{
result.Add((T2) rw.Read(RowList[i]));
// result.Add((T2) Convert.ChangeType(rw.Read(RowList[i]), typeof(T2)));
}
return result;
}
public List<T2> GetListByColumnWithClassType<T2>(int column) where T2 : class
{
ReadWriteMethod rw = MethodInfoList[column];
List<T2> result = new List<T2>();
for (int i = 0; i < RowList.Count; i++)
{
result.Add(rw.Read(RowList[i]) as T2);
}
return result;
}
public List<T2> GetListByColumnIndex<T2>(int column)
{
List<T2> result;
Type type = typeof(T2);
if (type.IsClass)
{
MethodInfo miConstructed = MethodInfoGetListByColumnWithClassType
.MakeGenericMethod(type);
result = miConstructed.Invoke(
null,
new object[] {column}
) as List<T2>;
}
else
{
result = GetListByColumnWithForcedType<T2>(column);
}
return result;
}
public List<T2> GetListByFieldName<T2>(string fieldName) =>
GetListByColumnIndex<T2>(GetColumnIndexByFieldName(fieldName));
/// <summary>
/// 按 字段类型 查询列记录。
/// (注意!这只会引索到同类型的其中一个!
/// 最好是在类型不重复的情况下使用)
/// </summary>
public List<T2> GetListByFieldType<T2>() =>
GetListByColumnIndex<T2>(GetColumnIndexByFieldType(typeof(T2)));
public void ThrowNotSupport(MethodBase methodInfo)
{
throw new NotSupportedException("Does not support " + methodInfo.Name + " operation.");
}
public void Add(T item)
{
bool isFound = false;
int row = RowList.Count;
RowList.Add(item);
for (; row < RowList.Count; row++)
{
if (RowList[row].Equals(item))
{
isFound = true;
break;
}
}
if (!isFound)
{
throw new InvalidOperationException("List member changed while adding item is not complete.");
}
//遍历每一列
for (int column = 0; column < MemberInfoList.Count; column++)
{
ReadWriteMethod rw = MethodInfoList[column];
ConcurrentDictionary<object, List<int>> db = RowIndexDatabase[column];
object key = rw.Read(item);
if (NoIndex4Null && null == key)
{
continue;
}
List<int> columnIndexList = db.GetOrAdd(key, new List<int>());
columnIndexList.Add(row);
}
}
public void Clear()
{
// RowList.Clear();
ThrowNotSupport(MethodBase.GetCurrentMethod());
}
public bool Contains(T item)
{
return RowList.Contains(item);
}
public int IndexOf(T item)
{
return RowList.IndexOf(item);
}
public bool Remove(T item)
{
ThrowNotSupport(MethodBase.GetCurrentMethod());
return false;
// return RowList.Remove(item);
}
public void Insert(int index, T item)
{
ThrowNotSupport(MethodBase.GetCurrentMethod());
// RowList.Insert(index, item);
}
public void RemoveAt(int index)
{
ThrowNotSupport(MethodBase.GetCurrentMethod());
// RowList.RemoveAt(index);
}
public int Count => RowList.Count;
// public bool IsReadOnly => false;
public T this[int row]
{
get => RowList[row];
set
{
T newItem = value;
T oldItem = RowList[row];
//遍历每一列
for (int column = 0; column < MemberInfoList.Count; column++)
{
ReadWriteMethod rw = MethodInfoList[column];
ConcurrentDictionary<object, List<int>> db = RowIndexDatabase[column];
object newKey = rw.Read(newItem);
object oldKey = rw.Read(oldItem);
if (!oldKey.Equals(newKey))
{
List<int> columnIndexList;
columnIndexList = db.GetOrAdd(oldKey, new List<int>());
columnIndexList.Remove(row);
if (columnIndexList.Count == 0)
db.TryRemove(oldKey, out _);
if (NoIndex4Null && null == newKey)
{
continue;
}
columnIndexList = db.GetOrAdd(newKey, new List<int>());
columnIndexList.Add(row);
}
}
RowList[row] = newItem;
}
}
public IEnumerator<T> GetEnumerator()
{
return RowList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void CopyTo(T[] array) => CopyTo(array, 0);
public void CopyTo(int index, T[] array, int arrayIndex, int count)
{
T[] rowListArray = RowList.ToArray();
if (rowListArray.Length - index < count)
throw new ArgumentOutOfRangeException();
Array.Copy(rowListArray, index, (Array) array, arrayIndex, count);
}
public void CopyTo(T[] array, int arrayIndex)
{
RowList.CopyTo(array, arrayIndex);
}
}
}