C# 中具有自定义集合的元素指标

本文关键字:元素 集合 自定义 | 更新日期: 2023-09-27 18:31:22

我正在尝试找出组织一堆数据类的最佳方式,因为我需要能够在某个时候访问它们的一些指标。

这是我的OR类的一个片段:

public enum status { CLOSED, OPEN }
public class OR
{
    public string reference { get; set; }
    public string title { get; set; }
    public status status { get; set; }
}

并非我初始化的每个 OR 都会有所有属性的值。我希望能够以这样一种方式将数千个这些对象"收集"在一起,以便我可以轻松获得有多少OR对象设置了值。例如:

OR a = new OR() { reference = "a" }
OR b = new OR() { reference = "b", title = "test" }
OR c = new OR() { reference = "c", title = "test", status = status.CLOSED }

现在这些以某种方式以我可以做的方式收集(伪):

int titleCount = ORCollection.titleCount;
titleCount = 2

我还希望能够收集枚举类型属性的指标,例如从集合中检索如下所示的Dictionary

Dictionary<string, int> statusCounts = { "CLOSED", 1 }

想要访问这些指标的原因是,我正在构建两个 OR 集合,并并排比较它们是否存在任何差异(它们应该是相同的)。我希望能够首先在这个更高的级别上比较他们的指标,然后细分他们之间的确切差异。

感谢您对如何实现这一目标的任何了解。

C# 中具有自定义集合的元素指标

。"收集"数以千计的这些

数千人并不是一个很大的数字。只需使用List<OR>,即可通过 Linq 查询获取所有指标。

例如:

List<OR> orList = ...;
int titleCount = orList
       .Where(o => ! string.IsNullOrEmpty(o.title))
       .Count(); 
Dictionary<status, int> statusCounts = orList
        .GroupBy(o => o.status)
        .ToDictionary(g => g.Key, g => g.Count());

使用 Linq 的现有答案绝对很棒而且非常优雅,所以下面提出的想法只供后人参考。

这是一个(非常粗略的)基于反射的程序,它将引导您计算任何对象集合中的"有效"属性。

验证器由

您在验证器字典中定义,以便您可以轻松更改每个属性的有效/无效值。如果您最终得到的对象具有大量属性,并且不想为每个属性在实际集合本身上编写内联 linq 指标,您可能会发现它作为一个概念很有用。

您可以将其武器化为一个函数,然后针对两个集合运行它,从而为您提供报告两者之间确切差异的基础,因为它在最终字典中记录了对各个对象的引用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace reftest1
{
    public enum status { CLOSED, OPEN }
    public class OR 
    {
        public string reference { get; set; }
        public string title { get; set; }
        public status status { get; set; }
        public int foo { get; set; }
    }
    //creates a dictionary by property of objects whereby that property is a valid value
    class Program
    {
        //create dictionary containing what constitues an invalid value here
        static Dictionary<string,Func<object,bool>> Validators = new Dictionary<string, Func<object,bool>>
            {
                {"reference", 
                    (r)=> { if (r ==null) return false;
                              return !String.IsNullOrEmpty(r.ToString());}
                },
                {"title",
                    (t)=> { if (t ==null) return false;
                              return !String.IsNullOrEmpty(t.ToString());}
               }, 
               {"status", (s) =>
                    {
                        if (s == null) return false;
                        return !String.IsNullOrEmpty(s.ToString());
              }},
             {"foo",
                 (f) =>{if (f == null) return false;
                            return !(Convert.ToInt32(f.ToString()) == 0);}
                    }
            };
        static void Main(string[] args)
        {
            var collection = new List<OR>();
            collection.Add(new OR() {reference = "a",foo=1,});
            collection.Add(new OR(){reference = "b", title = "test"});
            collection.Add(new OR(){reference = "c", title = "test", status = status.CLOSED});
            Type T = typeof (OR);
            var PropertyMetrics = new Dictionary<string, List<OR>>();
            foreach (var pi in GetProperties(T))
            {
                PropertyMetrics.Add(pi.Name,new List<OR>());
                foreach (var item in collection)
                {
                    //execute validator if defined
                    if (Validators.ContainsKey(pi.Name))
                    {
                       //get actual property value and compare to valid value
                       var value = pi.GetValue(item, null);
                       //if the value is valid, record the object into the dictionary
                       if (Validators[pi.Name](value))
                       {
                           var lookup = PropertyMetrics[pi.Name];
                           lookup.Add(item);
                       }
                    }//end trygetvalue
                }
            }//end foreach pi
            foreach (var metric in PropertyMetrics)
            {
                Console.WriteLine("Property '{0}' is set in {1} objects in collection",metric.Key,metric.Value.Count);
            }
            Console.ReadLine();
        }

        private static List<PropertyInfo> GetProperties(Type T)
        {
            return T.GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList();
        }
    }
}

可以使用以下 linq 查询获取标题计数:

int titleCount = ORCollection
                    .Where(x => !string.IsNullOrWhiteSpace(x.title))
                    .Count();

您可以像这样获得关闭的计数:

int closedCount = ORCollection
                     .Where(x => x.status == status.CLOSED)
                     .Count();

如果您要拥有更大的集合或经常访问值,则可能值得创建一个存储字段计数的自定义集合实现,然后它可以在添加和删除项目时递增/递减这些值。您还可以在此自定义集合中存储状态计数字典,该字典会在您添加和删除项目时更新。