我如何创建一个通用方法来比较任何类型的两个列表。该类型也可以是类的列表 [英] How can I create a generic method to compare two list of any type. The type may be a List of class as well
问题描述
以下是一个类
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屋!