Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic class can product identical signature overloads? [duplicate]

Tags:

c#

Possible Duplicate:
Generic methods and method overloading

Ok, I hit this one by accident... Giving this situation:

class Program {
    static void Main( string[ ] args ) {

        var obj = new gen<int>( );
        Console.Write( obj[ 1 ] );
        Console.ReadKey( );

    }
}

class gen<T> {

    public int this[ T i ] { get { return 2; } }

    public int this[ int i ] { get { return 1; } }

}

It will always print 1. I would have expected for the compiler to complain, or the runtime to crash and burn and melt the CPU, but no, it is happy to print '1'

Of course I can make a choice to return either if I use any other type for the generic parameter. For giggles, I try using UInt as the generic type parmater, and I can differentiate between the calls, so the questions are:

  1. Why C# does not freak out? Shouldn't Anders Hejlsberg feel a disturbance in the force?

  2. How can I restrict a generic parameter from certain types? As in this T can be anything but ints (but long are OK)

like image 644
JorgeLeo Avatar asked Dec 06 '22 11:12

JorgeLeo


2 Answers

I believe this is specified in section 7.5.3.2 of the C# 4 spec (Better Function Member).

  • Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ [...]
    • A type parameter is less specific than a nontype parameter
    • [...]

So here, the member with the T parameter is less specific than the member with the int parameter.

Try to design your way out of this one simply by not overloading like this. It's hard for indexers of course, but you could always provide methods instead (or possibly as well, as a fall-back).

EDIT: Note that if you have overloaded methods where both are type parameters, the compiler will complain:

public class Foo<T1, T2>
{
    public void Bar(T1 t1) {}
    public void Bar(T2 t2) {}
}

...

Foo<int, int> foo = new Foo<int, int>();
foo.Bar(10); // Error

Here neither method is more specific.

How can I restrict a generic parameter from certain types? As in this T can be anything but ints (but long are OK)

This is really an entirely separate question, but basically you can't. You can constrain type parameters in various ways, but not by explicitly including and excluding types. See the MSDN page on constraints for more information.

like image 101
Jon Skeet Avatar answered Dec 10 '22 01:12

Jon Skeet


As Eric Lippert says:

The C# specification says that when you have a choice between calling ReallyDoIt(string) and ReallyDoIt(string) – that is, when the choice is between two methods that have identical signatures, but one gets that signature via generic substitution – then we pick the “natural” signature over the “substituted” signature.

Also this process described in C# spec 7.5.3.2 (Better function member):

In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.

  • If MP is a non-generic method and MQ is a generic method, then MP is better than MQ (as John pointed, this is true when you have generic method, not generic type)
  • ...
  • Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ. Let {R1, R2, …, RN} and {S1, S2, …, SN} represent the uninstantiated and unexpanded parameter types of MP and MQ. MP’s parameter types are more specific than MQ’s if, for each parameter, RX is not less specific than SX, and, for at least one parameter, RX is more specific than SX:

    • A type parameter is less specific than a non-type parameter (this is your case - thus methods are not generic, and inferred parameter type equals to non-generic parameter type)
like image 44
Sergey Berezovskiy Avatar answered Dec 10 '22 02:12

Sergey Berezovskiy