How to use the same interface twice with different template parameters in the interface?

I think it will be more clear with this example. We want to see two methods with different parameters in the processor class. "int Process (int value)"; "double Process (double value);"

But the compiler says for IRoot: "Generics.IRoot" cannot implement both "Generics.IProcess" and "Generics.IProcess", because they can be combined for some type parameter substitutions.

public class Processor : IRoot<int, double, int, double> { // Here we want 2 methods public int Process(int item) { } public double Process(double item) { } } public interface IProcess<TResult, TItem> { TResult Process(TItem item); } public interface IRoot<TR1, TR2, TItem1, TItem2> : IProcess<TR1, TItem1>, IProcess<TR2, TItem2> { } 
+4
generics c #
Aug 17 '09 at 9:30 a.m.
source share
6 answers

You can probably use such an implementation. You will lose some general arguments:

 public interface IBase<TM, TPkey> where TM : bType where TPkey : new () { TM Get(TPkey key); } public interface IABase<TPK> : IBase<ConcreteTmA, TPK> {} public interface IBBase<TPK> : IBase<ConcreteTmB, TPK> {} public class Root <TPK> : IABase<TPK>, IBBase<TPK> where TM : MType where TPM : PMType where TPK : new() { ConcreteTmA IABase.Get(TPK key) { } ConcreteTmB IBBase.Get(TPK key) { } } 
-3
Aug 17 '09 at 10:11
source share

So, after posting my first answer to this question (# 1) , I realized that it often needs to be converted from a differentiated interface to an undifferentiated interface. In other words, you want to do the following

 IProcessWithDifferentiator<TRes, TItem, TDiff> : IProcess<TRes, TItem> 

but we cannot, because when using the interface we will encounter the same error (types can be combined).

I note that the OP did not specifically ask for this, but you can see that this will be the next logical scenario.

So, back to the drawing board and back with an ugly solution for this, which is that the method returns the converted type down and a proxy server to support the construction of such methods. (The only mitigation of ugliness is that the proxy class can be repeated a bit, as shown below.) The following is the result of this exercise.

 public interface Second { } public interface Third { } public class Processor : IRoot<float, int, double, float, int, double> { // Here we want 3 methods public float Process ( float item ) { System.Console.WriteLine ( " ...float Process..." ); return (float) (item - 55.75); } public int Process ( int item ) { System.Console.WriteLine ( " ...int Process..." ); return item + 1; } public double Process ( double item ) { System.Console.WriteLine ( " ...double Process..." ); return item + 10.748; } IProcess<int, int> IProcessWithDifferentiator<int, int, Second>.ConvertToBase () { return new TP_Proxy<int, int, Second> ( this ); } IProcess<double, double> IProcessWithDifferentiator<double, double, Third>.ConvertToBase () { return new TP_Proxy<double, double, Third> ( this ); } } public class TestProcessor : IRoot<int, int, int, int, int, int> { int IProcess<int, int>.Process ( int item ) { System.Console.WriteLine ( " ...int Process1..." ); return item - 11; } int IProcessWithDifferentiator<int, int, Second>.Process ( int item ) { System.Console.WriteLine ( " ...int Process2..." ); return item + 12; } int IProcessWithDifferentiator<int, int, Third>.Process ( int item ) { System.Console.WriteLine ( " ...int Process3..." ); return item + 100302; } IProcess<int, int> IProcessWithDifferentiator<int, int, Second>.ConvertToBase () { return new TP_Proxy<int, int, Second> ( this ); } IProcess<int, int> IProcessWithDifferentiator<int, int, Third>.ConvertToBase () { return new TP_Proxy<int, int, Third> ( this ); } } public interface IProcess<TResult, TItem> { TResult Process ( TItem item ); } public interface IProcessWithDifferentiator<TResult, TItem, TDiff> // would love to ": IProcess<TResult, TItem>" here but won't work above { TResult Process ( TItem item ); // replicated method from IProcess... yuck(!) IProcess<TResult, TItem> ConvertToBase (); } // Having a proxy sucks. But at least this proxy is shared among multiple classes implementing the IProcess concept. class TP_Proxy<TResult, TItem, TDiff> : IProcess<TResult, TItem> { public TP_Proxy ( IProcessWithDifferentiator<TResult, TItem, TDiff> px ) { _proxyTo = px; } private IProcessWithDifferentiator<TResult, TItem, TDiff> _proxyTo; TResult IProcess<TResult, TItem>.Process ( TItem item ) { return _proxyTo.Process ( item ); } } public interface IRoot<TR1, TR2, TR3, TItem1, TItem2, TItem3> : IProcess<TR1, TItem1>, IProcessWithDifferentiator<TR2, TItem2, Second>, IProcessWithDifferentiator<TR3, TItem3, Third> { } class Program { static void Main ( string [] args ) { Processor p = new Processor (); // Direct conversion of first one, of course IProcess<float, float> a1 = p; System.Console.WriteLine ( "a1 .Process(3.3) = " + a1.Process ( (float) 3.3 ) ); // Conversion of differentiated class IProcessWithDifferentiator<int, int, Second> a2 = ((IProcessWithDifferentiator<int, int, Second>) p); System.Console.WriteLine ( "a2d.Process(4) = " + a2.Process ( 4 ) ); IProcessWithDifferentiator<double, double, Third> a3 = (IProcessWithDifferentiator<double, double, Third>) p; System.Console.WriteLine ( "a3d.Process(5.5) = " + a3.Process ( 5.5 ) ); // Conversions to undifferentiated class using ugly proxies IProcess<int, int> a2u = ((IProcessWithDifferentiator<int, int, Second>) p).ConvertToBase (); System.Console.WriteLine ( "a2u.Process(4) = " + a2u.Process ( 4 ) ); IProcess<double, double> a3u = ((IProcessWithDifferentiator<double, double, Third>) p).ConvertToBase (); System.Console.WriteLine ( "a3u.Process(5.5) = " + a3u.Process ( 5.5 ) ); TestProcessor q = new TestProcessor (); IProcess<int, int> b1 = q; // Direct conversion of first one, of course System.Console.WriteLine ( "b1 .Process(3) = " + b1.Process ( 3 ) ); // Conversion of differentiated class IProcessWithDifferentiator<int, int, Second> b2d = (IProcessWithDifferentiator<int, int, Second>) q; System.Console.WriteLine ( "b2d.Process(4) = " + b2d.Process ( 4 ) ); IProcessWithDifferentiator<int, int, Third> b3d = (IProcessWithDifferentiator<int, int, Third>) q; System.Console.WriteLine ( "b3d.Process(5) = " + b3d.Process ( 5 ) ); // Conversions to undifferentiated class using ugly proxies IProcess<int, int> b2u = ((IProcessWithDifferentiator<int, int, Second>) q).ConvertToBase (); System.Console.WriteLine ( "b2u.Process(4) = " + b2u.Process ( 4 ) ); IProcess<int, int> b3u = ((IProcessWithDifferentiator<int, int, Third>) q).ConvertToBase (); System.Console.WriteLine ( "b3u.Process(5) = " + b3u.Process ( 5 ) ); System.Console.ReadLine (); } } 

The output is as follows:

  ...float Process... a1 .Process(3.3) = -52.45 ...int Process... a2d.Process(4) = 5 ...double Process... a3d.Process(5.5) = 16.248 ...int Process... a2u.Process(4) = 5 ...double Process... a3u.Process(5.5) = 16.248 ...int Process1... b1 .Process(3) = -8 ...int Process2... b2d.Process(4) = 16 ...int Process3... b3d.Process(5) = 100307 ...int Process2... b2u.Process(4) = 16 ...int Process3... b3u.Process(5) = 100307 
+3
Sep 11 '12 at 19:02
source share

The problem is precisely the error message:

 'IRoot<TM,TPM,TPK>' cannot implement both 'IBase<TM,TPK>' and 'IBase<TPM,TPK>' because they may unify for some type parameter substitutions 

For example, you can do this:

 public class Test : IRoot<Int32, Int32, Int32> 

and in this case it should have two inheritance chains IBase<Int32, Int32> , which are not allowed.

As always, try to include the problem you are facing, as well as the code with this problem.

+2
Aug 17 '09 at 10:00
source share

Here is my solution. This is based on the use of differentiation so that you can understand which interface you need. You must add another unused parameter, but what tells it what you want.

 public interface First { } public interface Second { } public class Processor : IRoot<int, double, int, double> { // Here we want 2 methods public int Process ( int item ) { System.Console.WriteLine ( "int Process" ); return item + 1; } public double Process ( double item ) { System.Console.WriteLine ( "double Process" ); return item + 10.748; } } public class TestProcessor : IRoot<int, int, int, int> { int IProcessWithDifferentiator<int, int, First>.Process ( int item ) { System.Console.WriteLine ( "int Process" ); return item + 1; } int IProcessWithDifferentiator<int, int, Second>.Process ( int item ) { System.Console.WriteLine ( "int Process" ); return item + 100302; } } public interface IProcessWithDifferentiator<TResult, TItem, TDiff> { TResult Process ( TItem item ); } public interface IRoot<TR1, TR2, TItem1, TItem2> : IProcessWithDifferentiator<TR1, TItem1, First>, IProcessWithDifferentiator<TR2, TItem2, Second> { } class Program { static void Main ( string [] args ) { Processor p = new Processor (); IProcessWithDifferentiator<int, int, First> one = p; System.Console.WriteLine ( "one.Process(4) = " + one.Process ( 4 ) ); IProcessWithDifferentiator<double, double, Second> two = p; System.Console.WriteLine ( "two.Process(5.5) = " + two.Process ( 5.5 ) ); TestProcessor q = new TestProcessor (); IProcessWithDifferentiator<int, int, First> q1 = q; System.Console.WriteLine ( "q1.Process(4) = " + q1.Process ( 4 ) ); IProcessWithDifferentiator<int, int, Second> q2 = q; System.Console.WriteLine ( "q2.Process(5) = " + q2.Process ( 5 ) ); System.Console.ReadLine (); } } 

Here is the conclusion.

 int Process one.Process(4) = 5 double Process two.Process(5.5) = 16.248 int Process q1.Process(4) = 5 int Process q2.Process(5) = 100307 

This will work even if you use IRoot<int,int,int,int> , as you can see above; he knows (because we are telling it) which IDifferentiatedProcess to use.

(In case that matters, I'm on Visual Studio 2012.)

+2
Sep 11 '12 at 1:05
source share

From what I understand, you want to define an interface similar to this:

 public interface IRoot<TM, TPM, TPK> where TM : MType where TPM : PMType where TPK : new() { TM Get(TPK key); TPM Get(TPK key); } 

And this is not possible because you cannot define two methods with the same name and the same parameters.

 error CS0111: Type 'IRoot<TM,TPM,TPK>' already defines a member called 'Get' with the same parameter types 

Try defining your interface directly (without inheritance) and change the method names. For example:

 public interface IRoot<TM, TPM, TPK> where TM : MType where TPM : PMType where TPK : new() { TM GetTM(TPK key); TPM GetTPM(TPK key); } 
+1
Aug 17 '09 at 9:54
source share

Sorry that you had so many downvotes, I ran into the same problem.

Unfortunately, this is not possible - only possible restrictions of a general type are listed on this MSDN page, and no one can express the restriction " T and U can be any types, but must have different inheritance hierarchies" http://msdn.microsoft.com /en-us/library/d5x73970(v=vs.80).aspx

We really need some kind of syntax where T !: U or where T, U disjoint ; but in its current form, it is impossible to tell the compiler that instances of TItem1 and TItem2 never be interchangeable for each other.

+1
Jan 06 2018-12-12T00:
source share



All Articles