【问题标题】:How can I create a generic method to compare two list of any type. The type may be a List of class as well如何创建一个通用方法来比较任何类型的两个列表。类型也可以是类列表
【发布时间】:2016-02-18 11:42:52
【问题描述】:

下面是一个类

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

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

{
            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 不允许我们这样做。但是有没有其他方法可以让我投射这个通用列表。我的目的是比较这两个列表的每个属性值。我正在使用反射来获取属性,但只有当我可以将 firstlist/secondlist 转换为可枚举的东西时它才有效。如果我直接在IList&lt;&gt; 中使用类的名称(firstList 作为IList&lt;Attribute&gt;)它可以工作,但如果我给&lt;T&gt; 则不行。请帮忙。

【问题讨论】:

标签: c# list generics


【解决方案1】:

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

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>());

【讨论】:

    【解决方案2】:

    更改方法的签名并删除多余的演员表:

    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;
    }
    

    【讨论】:

    • 我已经按照您的建议做了,但是当我调用 CompareList 方法时,它会说类似“类型 Generic,List 不能用作泛型类型中的类型参数 'T'或方法”
    【解决方案3】:
    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; 
        }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-02
      • 2021-02-19
      • 1970-01-01
      • 1970-01-01
      • 2020-07-09
      • 2022-01-19
      • 1970-01-01
      • 2014-11-12
      相关资源
      最近更新 更多