Search code examples
c#comparetosorteddictionary

Error while fetching data from sorted dictionary in C#


I have a SortedDictionary<Package, List<string>>. Following is the Package class:

using System;

namespace GetPackageInfo
{

public class Package : IComparable, IEquatable<Package> 
{
    public string PackageName;
    public string Version;

    public Package()
    {

    }

    public Package(string packageName)
    {
        this.PackageName = packageName;
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int result = 17;
            result = result * 23 + ((PackageName != null) ? this.PackageName.GetHashCode() : 0);
            result = result * 23 + ((Version != null) ? this.Version.GetHashCode() : 0);
            return result;
        }
    }

    public bool Equals(Package other)
    {
        if (ReferenceEquals(null, other))
        {
            return false;
        }
        if (ReferenceEquals(this, other))
        {
            return true;
        }
        return Equals(this.PackageName, other.PackageName) &&
               Equals(this.Version, other.Version);
    }

    public override bool Equals(object obj)
    {
        Package temp = obj as Package;
        if (temp == null)
            return false;
        return this.Equals(temp);
    }

    public override string ToString()
    {
        return string.Format("PackageName: {0}, Version: {1}", PackageName, Version);
    }

    public int CompareTo(object obj)
    {
        if (obj == null)
            return 1;

        if (obj != null) 
            return (Equals(obj) ? -1 : 1);
        else
            throw new ArgumentException("Object is not a Temperature");
    }

Whenever I do a Contains or ContainsKey on the SortedDictionary, it does not work even when the name and version is the same.

if (nugetPackagesInfo.Keys.Any(p => p.Equals(package)))
{
    //List<string> currPackage;
    //nugetPackagesInfo.TryGetValue(package, out currPackage);
    if (!nugetPackagesInfo[package].Contains(packageFile))
    {
        nugetPackagesInfo[package].Add(packageFile);
    }

nuGetPackagesInfo is my dictionary object. The Any returns true though. But once it is passed and gets to nugetPackagesInfo[package], then it throws the KeyNotFoundException. Can you please help me figure it out? Is my CompareTo not correct?


Solution

  • Change CompareTo and GetHashCode to these implementations.

    public int CompareTo(object obj)
    {
        if (obj == null)
            return 1;
        return this.ToString().CompareTo(obj.ToString());
    }
    public override int GetHashCode()
    {
        unchecked
        {
            return ((PackageName != null ? PackageName.GetHashCode() : 0)*397) ^ (Version != null ? Version.GetHashCode() : 0);
        }
    }
    
    public override string ToString()
    {
        return string.Format("PackageName: {0}, Version: {1}", PackageName??"", Version ?? "");
    }
    

    CompareTo - see the documentation. By using ToString() you get a comparison on the package name and then the version without having to do your own checks. Just make sure that ToString is correct (I added null check so it does not throw an Exception).

    GetHashCode - not sure where you got your implementation from. You need to make sure that the hashcode is always unique for that item unless they truely are equal. This is the implementation I found on this previous answer on SO, see the last edit in the answer..