Is there a suggestion that I can ask along the lines "where: TypeOf (T1)! = TypeOf (T2)"
You can force your constructor to throw an exception at runtime. But there is no way to prevent this situation during compilation.
Any way to make this unambiguous?
You must change the names of your methods so that they do not collide. This is by far the safest and easiest thing.
In fact, the IIRC CLR reserves the right not to create a type that creates ambiguity in such method signatures. (Obviously, our implementation actually succeeds, but you step on very thin ice when you pull out these kinds of frauds.)
Doing this kind of thing is really a very bad idea, because it can cause you all kinds of trouble. Here's an example of how things are going terribly wrong:
http://blogs.msdn.com/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx
http://blogs.msdn.com/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx
Also note that the compiler will stop you from creating a type, so that it implements two interfaces that can be identical when building. It is illegal:
class C<T, U> : IFoo<T>, IFoo<U> { ... }
because then you can build C<int, int> , and the CLR will not be able to find out which methods correspond to the interface slots.
But I seem to be a little distracted. Return to the topic.
Since you are the creator of this class, you can rename your Bar methods so that they are different for any possible construction. Suppose you stubbornly choose not to. Is there something that a user of your failed class can do if they want to make Widget<int, int> ? Yes, in fact, there is, as kvb points out. They can define extension methods that do the right thing.
public static void BarTheFirst<A, B>(this Widget<A, B> w, A a) { w.Bar(a); } public static void BarTheFirst<A, B>(this Widget<A, B> w, B b) { w.Bar(b); }
Overload resolution is performed at compile time, and at compile time all we know is that the first calls Bar, which takes "A", and the second calls Bar, which takes "B". We do not repeat overload resolution at runtime, so now you can say
Widget<int, int> w = whatever; w.BarTheFirst(5); w.BarTheSecond(10);
and he will go right.