如何创建一个泛型方法来比较任何类型的两个列表.类型也可以是类列表

本文关键字:类型 列表 两个 也可以 任何 创建 何创建 一个 泛型方法 比较 | 更新日期: 2023-09-27 18:35:21

下面是一个类

public class Attribute
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }

以下是我的主方法中的代码

{
            var test = new List<Attribute>();
            test.Add(new Attribute { Name = "Don", Value = "21" });
            test.Add(new Attribute { Value = "34", Name = "Karthik" });

            var test1 = new List<Attribute>();
            test1.Add(new Attribute { Name = "Don", Value = "21" });
            test1.Add(new Attribute { Value = "34", Name = "Karthik" });
            var obj = new Program();
            var areEqual1 = obj.CompareList<List<Attribute>>(test, test1);
}

我有一个ComapreList方法

public bool CompareList<T>(T firstList, T secondList) where T : class
        {
            var list1 = firstList as IList<T>;
            return true;
        }

现在,list1 具有空值。我知道.net不允许我们这样做。但是有没有其他方法可以投射这个通用列表。我的目的是比较这两个列表的每个属性值。我正在使用反射来获取属性,但仅当我可以将第一个列表/第二个列表转换为可枚举的内容时,它才有效。如果我直接在IList<>中使用类的名称(firstList IList<Attribute>),它可以工作,但如果我给<T>则不行。请帮忙。

如何创建一个泛型方法来比较任何类型的两个列表.类型也可以是类列表

只需创建按列表项目类型类型参数化的方法。更重要的是,您可以创建比较任何类型的集合的方法:

public bool CompareSequences<T> (IEnumerable<T> first, IEnumerable<T> second,
      Comparer<T> comparer = null)
{
    comparer = comparer ?? Comparer<T>.Default;
    if (first == null)
        throw new ArgumentNullException(nameof(first));
    if (second == null)
        throw new ArgumentNullException(nameof(second));
    var firstIterator = first.GetEnumerator();
    var secondIterator = second.GetEnumerator();
    while(true)
    {
        bool firstHasItem = firstIterator.MoveNext();
        bool secondHasItem = secondIterator.MoveNext();
        if (firstHasItem != secondHasItem)
            return false;
        if (!firstHasItem && !secondHasItem)
            return true;
        if (comparer.Compare(firstIterator.Current, secondIterator.Current) != 0)
            return false;
    }
}

如果集合项是基元类型,则可以使用默认比较器。但是,如果集合包含自定义项,则需要通过集合项类型实现任一IComparable

public class Attribute : IComparable<Attribute>
{
    public string Name { get; set; }
    public string Value { get; set; }
    public int CompareTo (Attribute other)
    {
        int result = Name.CompareTo(other.Name);
        if (result == 0)
            return Value.CompareTo(other.Value);
        return result;
    }
}

或者,您可以创建并传递比较器实例。您可以创建使用反射来比较某种类型的字段/属性的比较器。但它并不像你想象的那么简单 - 属性可以是复杂的类型或集合。

用法:

var areEqual1 = obj.CompareSequences(test, test1);

如果您不需要比较具有复杂结构的对象(具有内部集合和其他自定义对象),则可以使用如下所示的比较器:

public class SimplePropertiesComparer<T> : Comparer<T>
{
    public override int Compare (T x, T y)
    {
        Type type = typeof(T);
        var flags = BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance;
        foreach (var property in type.GetProperties(flags))
        {
            var propertyType = property.PropertyType;
            if (!typeof(IComparable).IsAssignableFrom(propertyType))
               throw new NotSupportedException($"{propertyType} props are not supported.");
            var propertyValueX = (IComparable)property.GetValue(x);
            var propertyValueY = (IComparable)property.GetValue(y);
            if (propertyValueX == null && propertyValueY == null)
                continue;
            if (propertyValueX == null)
                return -1;
            int result = propertyValueX.CompareTo(property.GetValue(y));
            if (result == 0)
                continue;
            return result;
        }
        return 0;
    }
}

并将其传递给序列比较器

var equal = obj.CompareSequences(test, test1, new SimplePropertiesComparer<Attribute>());

更改方法的签名并删除多余的强制转换:

public bool CompareList<T>(IList<T> firstList, IList<T> secondList) where T : class
{
    var list1 = firstList as IList<T>; // Cast is not necessary any more
    return true;
}
public bool CompareGenericLists<T, U>(List<T> list1, List<U> list2)
    {
        try
        {
            if (typeof(T).Equals(typeof(U)))
            {
                //For checking null lists
                if (list1 == null && list2 == null)
                    return true;
                if (list1 == null || list2 == null)
                    throw new Exception("One of the Lists is Null");
                if (list1.Count.Equals(list2.Count))
                {
                    Type type = typeof(T);
                    //For primitive lists
                    if (type.IsPrimitive)
                    {
                        int flag = 0;
                        for (int i = 0; i < list1.Count; i++)
                        {
                            if (list1.ElementAt(i).Equals(list2.ElementAt(i)))
                                flag++;
                        }
                        if (flag != list1.Count)
                            throw new Exception("Objects values are not same");
                }
                    //For Reference List
                    else
                    {
                        for (int i = 0; i < list1.Count; i++)
                        {
                            foreach (System.Reflection.PropertyInfo property in type.GetProperties())
                            {
                                string Object1Value = string.Empty;
                                string Object2Value = string.Empty;
                                Object1Value = type.GetProperty(property.Name).GetValue(list1.ElementAt(i)).ToString();
                                Object2Value = type.GetProperty(property.Name).GetValue(list2.ElementAt(i)).ToString();
                                if (Object1Value != Object2Value)
                                {
                                    throw new Exception("Objects values are not same");
                                }
                            }
                        }
                    }
                }
                else
                throw new Exception("Length of lists is not Same");
            }
            else
            throw new Exception("Different type of lists");
        }
        catch(Exception ex)
        {
            throw ex;
        }
            return true; 
    }
此方法

可用于基元列表和引用列表。请尝试此方法。它将比较列表的类型、计数和成员。