c# - 如何比较两个通用对象与嵌套集合

标签 c# .net generics recursion compare

我一直在研究一种通用方法来比较两个相同的对象,以测试每个对象中的值是否相等。

我一直在尝试比较 System.Collection.Generic 对象,例如 Dictionary、HashSet、LinkedList、Stack 等...

我可以比较的是 List 集合。

以下是我到目前为止所拥有的。如果您能提供一种比较泛型的方法,我将不胜感激。

~开始递归比较

public static bool FullCompare<T>(this T source, T compareTo, bool ignoreCase)
{
    return recursiveCompare(source, compareTo, ignoreCase, true);
}

~递归搜索

private static bool recursiveCompare<T>(T source, T compareTo, bool ignoreCase, bool isEqual)
{
    if (source == null || compareTo == null) return isEqual;
    if(!isEqual) return isEqual;

    Type sourceType = source.GetType();
    Type compareToType = compareTo.GetType();

    if (sourceType.IsPrimitive || source is string) return Test(source, compareTo, ignoreCase);  

    var sourceProperties = sourceType.GetProperties();
    var compareToProperties = compareToType.GetProperties();

    for (var property = 0; property < sourceProperties.Count(); property++ )
    {
        var sourceProperty = sourceProperties[property];
        var compareToProperty = compareToProperties[property];

        object sourceValue = sourceProperty.GetValue(source, null);
        object compareToValue = compareToProperty.GetValue(compareTo, null);

        var sourceElements = sourceValue as IList;
        var compareToElements = compareToValue as IList;

        if (sourceElements != null)
        {
            for (var element = 0; element < sourceElements.Count; element++)
            {
                isEqual = recursiveCompare(sourceElements[element], compareToElements[element], ignoreCase, isEqual);
            }
        }
        else if (typeof(IEnumerable).IsAssignableFrom(sourceProperty.PropertyType))
        {
            //compare System.Collection.Generic objects
        }
        else
        {
            if (sourceProperty.PropertyType.Assembly == sourceType.Assembly)
            {
                isEqual = recursiveCompare(sourceValue, compareToValue, ignoreCase, isEqual);
            }
            else
            {
                isEqual = Test(sourceValue, compareToValue, ignoreCase);
            }
        }
    }
    return isEqual;
}

~对比测试

private static bool Test<T>(T a, T b, bool ignoreCase)
{
    if (a == null && b == null)
    {
        return true;
    }
    else if (a == null)
    {
        return false;
    }
    else if (b == null)
    {
        return false;
    }
    else if (a is string)
    {
        if (ignoreCase)
        {
            var aAsString = Convert.ToString(a);
            var bAsString = Convert.ToString(b);
            return aAsString.EqualsIgnoreCaseAndWhitespace(bAsString);
        }
    }
    return EqualityComparer<T>.Default.Equals(a, b);
}

这些是我用来测试该功能的测试用例

    public class A
    {
        public string TestA { get; set; }
        public List<String> ListA { get; set; }
    }

    public class test
    {
        public byte? byte1 { get; set; }
        //public Dictionary<int, byte> byteDictionary { get; set; }
        public HashSet<byte> byteHashSet { get; set; }
        public LinkedList<byte> byteLinkedList { get; set; }
        public List<byte> byteList { get; set; }
        public Queue<byte> byteQueue { get; set; }
        public Stack<byte> byteStack { get; set; }
        public sbyte? sbyte1 { get; set; }
        public short? short1 { get; set; }
        public ushort? ushort1 { get; set; }
        public int? int1 { get; set; }
        public uint? uint1 { get; set; }
        public long? long1 { get; set; }
        public ulong? ulong1 { get; set; }
        public float? float1 { get; set; }
        public double? double1 { get; set; }
        public char? char1 { get; set; }
        public string string1 { get; set; }
        public decimal? decimal1 { get; set; }
        public bool? bool1 { get; set; }
        public DateTime datetime1 { get; set; }
        public TimeSpan timespan1 { get; set; }
        public string string1Var;
        public A objectA { get; set; }
    }

        var byteAList = new List<byte>();
        byteAList.Add(1);
        byteAList.Add(2);

        var byteBList = new List<byte>();
        byteBList.Add(1);
        byteBList.Add(2);

        //var byteADictionary = new Dictionary<int,byte>();
        //byteADictionary.Add(1,1);

        //var byteBDictionary = new Dictionary<int,byte>();
        //byteBDictionary.Add(1,1);

        var dateTimeA = new DateTime(1,1,1,1,1,1);            
        var dateTimeB = new DateTime(1,1,1,1,1,1);

        var timeSpanA = new TimeSpan(1,1,1,1,1);            
        var timeSpanB = new TimeSpan(1,1,1,1,1);

        var aAListAList = new List<string>();
        aAListAList.Add("Nel");
        aAListAList.Add("Hello");

        var aA = new A()
        {
            TestA = "Jar"
            , ListA = aAListAList
        };

        var aAListBList = new List<string>();
        aAListBList.Add("Nel");
        aAListBList.Add("Hello");
        var aB = new A()
        {
            TestA = "Jar"
            ,
            ListA = aAListBList
        };

        var byteHashSetA = new HashSet<byte>();
        byteHashSetA.Add(1);
        byteHashSetA.Add(2);

        var byteHashSetB = new HashSet<byte>();
        byteHashSetB.Add(1);
        byteHashSetB.Add(2);

        var a = new test() 
        { 
            byte1 = 1
            , byteList = byteAList
            //, byteDictionary = byteADictionary
            , byteHashSet = byteHashSetA
            , sbyte1 = -1
            , short1 = -11
            , ushort1 = 11
            , int1 = -1
            , uint1 = 1
            , long1 = 1
            , ulong1 = 1
            , float1 = 1.1F
            , double1  = 1.1
            //, char1 = 't'
            , string1 = "test"
            , decimal1 = 1.1M
            , bool1 = true
            , datetime1 = dateTimeA
            , timespan1 = timeSpanA 
            , string1Var = null
            , objectA = aA
        };
        var a2 = new test()
        {
            byte1 = 1
            ,
            byteList = byteBList
            //,
            //byteDictionary = byteBDictionary
            ,
            byteHashSet = byteHashSetB
            ,
            sbyte1 = -1
            ,
            short1 = -11
            ,
            ushort1 = 11
            ,
            int1 = -1
            ,
            uint1 = 1
            ,
            long1 = 1
            ,
            ulong1 = 1
            ,
            float1 = 1.1F
            ,
            double1 = 1.1
            ,
            char1 = 't'
            ,
            string1 = "test"
            ,
            decimal1 = 1.1M
            ,
            bool1 = true
            ,
            datetime1 = dateTimeB
            ,
            timespan1 = timeSpanB
            ,
            string1Var = null
            ,
            objectA = aB
        };

        var equal = a.FullCompare(a2, true);

最佳答案

我通过首先比较两个对象的长度解决了这个问题。然后,如果它们相同,那么我会执行一个嵌套循环来将一个列表与另一个列表进行比较。现在这可能效率不高,但它有效。

foreach (var sourceElement in sourceElements) { numOfSourceElements++; }

foreach (var compareToElement in compareToElements) { numOfCompareToElements++; }

if (numOfSourceElements != numOfCompareToElements) isEqual = false;

if (isEqual) 
{ 
    foreach (var sourceElement in sourceElements)
    {
        found = false;
        foreach (var compareToElement in compareToElements) 
        {
            if (IsSameAsRecursive(sourceElement, compareToElement, sameAsOptions, isEqual))
            {
                found = true;
                break;
            }
        }
        if (!found) break;
    }
    isEqual = found;
}

关于c# - 如何比较两个通用对象与嵌套集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24915621/

相关文章:

c# - 发送多个帖子请求

c# - 数组元素到结构约束方法

c# - 从 Roslyn 中的方法符号生成方法签名的语法

c# - 获取不带url参数的MVC路由路径

java - 调用不带参数的泛型函数

c# - 如何避免使用第 3 方 Web 服务的代码重复 - 不使用动态?

c# - C# 中的 XMl 反序列化器

c# - 桌面图标操作 - 当启用带有图片旋转的主题时如何获取 SysListView32 的句柄

c# - 为什么 xsd.exe 会为 xs :integer? 生成字符串属性

arrays - Typescript 泛型,获取数组内容的类型