C # Common Types Cause Ambiguity

I create my own universal class:

class Widget< T1, T2> { ... public bool Bar( T1 type1 ) { ... } public bool Bar( T2 type2 ) { ... } ... } 

The following lines, of course, create a compilation error for ambiguous calls:

 Widget<int, int> Foo = new Widget<int, int>(); ... Foo.Bar(5); ... 

Is there any way around this? Is there a suggestion that I can put in the lines "where: TypeOf (T1)! = TypeOf (T2)" or in any way make it unambiguous? Preferably, int, int will be available, but it is not a mandate.

Update:

I myself found an acceptable solution (for me) to this problem, for those who are interested

 class Widget< T1, T2> { ... public bool Bar( object o ) { if( o.GetType() == typeof(T1) ) { ... } if( o.GetType() == typeof(T2) ) { ... } } ... } 
+6
generics c #
source share
4 answers

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.

+18
source share

Give unique names to your functions

+5
source share

I agree with others that you should change your class so that a collision does not occur (for example, renaming methods). However, if you do not own the class, there is a workaround:

 public static class WidgetExtensions { public static bool Bar1<T1,T2>(this Widget<T1, T2> w, T1 t1) { return w.Bar(t1); } public static bool Bar2<T1,T2>(this Widget<T1, T2> w, T2 t2) { return w.Bar(t2); } } 

You can use these extension methods to cause the Bar to overload. Static methods should not be extension methods, but I think that makes it more understandable.

+1
source share

This is similar to the case when you need a base common class

 abstract class WidgetBase<T1> { public abstract bool Bar(T1 type); ... } 

Then inherit for your implementation

 class WidgetA : WidgetBase<int> { public bool Bar(int type) { ... } } class WidgetB : WidgetBase<int> { public bool Bar(int type) { ... } } 
0
source share

All Articles