Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# generic class and EqualityComparer

Could anyone explain me what's wrong in the following class declaration:

private class PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> :
        IComparer<PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType>>
            where TPriorityValue : IComparable
            where IIdentifiableEntry : Identifier<IType>
    {
        public TPriorityValue Priority{get;private set;}
        public IIdentifiableEntry Entry{get;private set;}

        public PriorityQueueEntry(TPriorityValue val,IIdentifiableEntry entry)
        {
            Priority = val;
            Entry = entry;
        }
        public int Compare(PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> first, PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> second) 
        {
            if (first.Priority.CompareTo(second.Priority) < 0)
            {
                return -1;
            }
            else if (first.Priority.CompareTo(second.Priority) > 0)
            {
                return 1;
            }
            return EqualityComparer<IIdentifiableEntry>.Default.Equals( first.Entry.Id, second.Entry.Id);
        }
    }

The compiler complaing on the line where I use EqualityComparer. The error is the following:

error CS0176: Static member `object.Equals(object, object)' cannot be accessed with an instance reference, qualify it with a type name instead

I can't see where I'm using an instance reference.


Sorry, my fault. I posted an incomplete question. Just for completeness, Idetifier class is just the following:

public interface Identifier<ID_TYPE> 
{
    ID_TYPE Id{get;set;}
}

using EqualityComparer there, was due to a copy and paste mistake(sorry guys, too much generic code today).

Of course my question was misposed, because I didn't give you all the elements you needed to answer (I'll remove it soon). I needed IType to be IConvertible. Thanks to all anyway.

like image 442
Heisenbug Avatar asked Nov 13 '12 12:11

Heisenbug


2 Answers

This is an instance reference:

EqualityComparer<IIdentifiableEntry>.Default

The first problem is that you don't want to call object.Equals(object, object) at all. You really want to be calling the method on the equality comparer - but you're trying to call it with arguments which aren't convertible to IIdentifieableEntry.

The second problem is that you're trying to perform an ordering comparison, not an equality comparison, so you want Comparer<T>, not EqualityComparer<T>.

It's not clear what you're trying to achieve, but this code would at least compile:

return Comparer<IIdentifiableEntry>.Default.Compare(first.Entry, second.Entry);

If you really want to compare the Id properties, you need an equality comparer for the ID property type - and we don't know what that type is.

I suspect it's more likely that you really want something like this:

return Comparer<string>.Default.Compare(first.Entry.Id, second.Entry.Id);

... but it depends on the type of Id.

like image 166
Jon Skeet Avatar answered Oct 09 '22 06:10

Jon Skeet


You have not shown the declaration of Identifier nor EqualityComparer. But I assume you need to change the line to something like:

return EqualityComparer<IIdentifiableEntry>.Default.Equals<IType>( first.Entry.Id, second.Entry.Id);

[EDIT]

As per Jon's comment. You do not want to equality comparer at all. Asumming that that Entry.Id is IComparable, then just:

return first.Entry.Id.CompareTo(second.Entry.Id);

I would recommend that Entry is restricted to IComparable, so we get something like:

class PriorityQueueEntry> where TPriorityValue : IComparable where TEntry : IComparable { public TPriorityValue Priority{get;private set;} public TEntry Entry{get;private set;}

    public PriorityQueueEntry(TPriorityValue val, TIdentifiableEntry entry)
    {
        Priority = val;
        Entry = entry;
    }
    public int Compare(PriorityQueueEntry<TPriorityValue, TEntry first, PriorityQueueEntry<TPriorityValue, TEntry> second) 
    {
        if (first.Priority.CompareTo(second.Priority) < 0)
        {
            return -1;
        }
        else if (first.Priority.CompareTo(second.Priority) > 0)
        {
            return 1;
        }
        return first.Enrtry.CompareTo(second.Entry);
    }
}

You may want to add some null checks if TEntry is a class.

like image 20
Richard Schneider Avatar answered Oct 09 '22 06:10

Richard Schneider