我如何创建一个通用方法来比较任何类型的两个列表。该类型也可以是类的列表 [英] How can I create a generic method to compare two list of any type. The type may be a List of class as well

查看:101
本文介绍了我如何创建一个通用方法来比较任何类型的两个列表。该类型也可以是类的列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是一个类

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

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

  {
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)其中T:class 
{
var list1 = firstList as IList< T>;

返回true;

}

现在,list1为空。我知道.net不允许我们这样做。但是有没有其他办法可以在这个通用名单上施展。我的目的是比较这两个列表的每个属性值。我使用反射来获取属性,但只有当我可以将firstlist / secondlist转换为enumerable时才有效。如果我直接在 IList> firstList 中使用 IList< Attribute> )它可以工作,但如果我给< T> ,则不会。请帮助。

解决方案

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

  public bool CompareSequences< T> (IEnumerable< T> first,IEnumerable< T> second,
Comparer< T> comparer = null)
{
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;






如果集合项是基本类型,那么可以使用default比较器。但是,如果集合包含自定义项目,则需要通过集合项目实现 IComparable 类型:

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

返回结果;
}
}

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



用法:

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






如果您不需要将对象与复杂的结构(它有内部集合和其他自定义对象),那么你可以使用像这样的比较器:

  public class SimplePropertiesComparer< T> ; :比较器< T> 
{
public override int Compare(T x,T y)
{
Type type = typeof(T);
var flags = BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance;

foreach(type.GetProperties(flags)中的var属性)
{
var propertyType = property.PropertyType;
if(!typeof(IComparable).IsAssignableFrom(propertyType))
throw new NotSupportedException(${propertyType} props is 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;

返回结果;
}

返回0;
}
}

并将它传递给序列比较器

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


Following is a class

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

Following is the code in my main method

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

I have a ComapreList method

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

            return true;

        }

Now, list1 has null. I know that .net does not allow us to do this. But is there any other way where I can cast this generic list. My purpose is to compare each property value of these two list. I am using reflection to get the property but it works only if I can convert the firstlist/secondlist to something enumerable. if I directly use the name of the class in the IList<> (firstList as IList<Attribute>) it works, but not if I give <T>. Please help.

解决方案

Just create method parameterized by type of lists items type. Even more, you can create method which compares any type of collections:

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

If collection items are primitive types, you can use default comparer. But if collections contain custom items, you need either IComparable to be implemented by collection items type:

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

Or you can create and pass comparer instance. You can create comparer which is using reflection to compare fields/properties of some type. But it's not as simple as you might think - properties can be complex type or collections.

Usage:

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


If you don't need to compare objects with complex structure (which have inner collections and other custom objects) then you can use comparer like this one:

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

And pass it to sequence comparer

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

这篇关于我如何创建一个通用方法来比较任何类型的两个列表。该类型也可以是类的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆