MrDosu
MrDosu

Reputation: 3435

Operator overloading with generic function parameters

I have a problem with operator resolution on generic methods.

From my understanding of section 7.3.4 of the spec within the function EqualOperatorGeneric (sample code below) the correct overload of the == operator on the type A should be found, but instead it seems to get the candidate for (object, object).

Am I doing something very obvious wrong? Is there a method to get the expected behaviour and if not can I turn the given case into a compile time or runtime error?

public class A
{
    public A(int num)
    {
        this.Value = num;
    }

    public int Value { get; private set; }

    public override bool Equals(object obj)
    {
        var other = obj as A;
        if (Object.ReferenceEquals(other, null))
            return false;

        return Object.Equals(this.Value, other.Value);
    }

    public override int GetHashCode()
    {
        return this.Value.GetHashCode();
    }

    public static bool operator ==(A l, A r)
    {
        if (Object.ReferenceEquals(l, null))
        {
            return !Object.ReferenceEquals(r, null);
        }

        return l.Equals(r);
    }

    public static bool operator !=(A l, A r)
    {
        return !(l == r);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(EqualOperatorGeneric(new A(1), new A(1)));
    }

    public static bool EqualOperatorGeneric<L, R>(L l, R r)
        where L : class
        where R : class
    {
        return l == r;
    }
}

Output:

False

Upvotes: 1

Views: 401

Answers (2)

MrDosu
MrDosu

Reputation: 3435

After scrounging the spec I realized you can use the dynamic keyword to defer binding of the operator from compile time to runtime. This fixes the issues I have been having:

public static bool EqualOperatorGeneric<L, R>(L l, R r)
{
    dynamic dl = l, dr = r;
    return dl == dr;
}

Upvotes: 1

Servy
Servy

Reputation: 203820

When EqualOperatorGeneric is compiled the == operator needs to be bound statically, when the method is compiled, to a single implementation. It is not bound separately for each separate usage of the generic method.

This is what differentiates generics from, say, C++ templates. The generic method is compiled once and then applied to every usage with every set of type arguments, whereas templates are compiled separately for each set of generic arguments.

Upvotes: 2

Related Questions