C# 7.3 .Net 4.6.1 如何将一个对象里的任意字段作为键去找这个对象

本文介绍了一种针对常量数据的高效C#集合类,利用空间换取时间,支持并发和快速查询,通过反射实现泛型操作,尤其适合只增不减的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写了一个超级吃内存的“疯狂数据库”。用空间换时间。
本集合可以拓展一下作为一个泛型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);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值