5

I Think it would be more clearer with this example. We Want to see two methods with diferrent parameters in the processor class. "int Process (int value);" "double Process (double value);"

But compiler says for IRoot : 'Generics.IRoot' cannot implement both 'Generics.IProcess' and 'Generics.IProcess' because they may unify 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>
{

}
jack-london
  • 1,599
  • 3
  • 21
  • 42
  • 1
    What's the question ? it's absolutely not clear from your code... Give some details and explanations, not just a piece of code ! – Thomas Levesque Aug 17 '09 at 09:47
  • Question is in the header: "How to use same interface two times with diferrent template parameters, in an interface?" – jack-london Aug 17 '09 at 10:45
  • The problem is that the only way we can try to figure out *why* you can't do this is to copy and paste the code into a compiler, and try to compile it. You should post the error message you get from the compiler, which makes it easier for people to answer. Never assume people will bother to jump through lots of hoops in order to help you, help us help you, provide us with as much information as possible. – Lasse V. Karlsen Aug 17 '09 at 11:17

6 Answers6

5

Here's my solution. It's based on using differentiation so you can be clear about which interface you want. You have to add an otherwise unused parameter, but that's what tells it which 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's the output.

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; it knows (because we tell it) which IDifferentiatedProcess to use.

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

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
3

So after posting my first answer to this question (#1), I then realized that one often might want to be able to convert a value from a differentiated interface to a non-differentiated interface. In other words, one wants to do the following

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

but we cannot because we'll run into the same error (types might unify) when using the interface.

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

So, back to the drawing board, and returning with an ugly solution for this, which is that of having a method return the down converted type, and a proxy to support construction of such methods. (The only mitigation of ugliness is that the proxy class can be somewhat reused as shown below.) 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
Community
  • 1
  • 1
Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
2

The problem is exactly what the error message says:

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

For instance, you can do this:

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

in which case it would have two inheritance chains to IBase<Int32, Int32> which is not allowed.

As always, please try to include the problem you're facing as well as the code with the problem.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
1

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

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 can't 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 to define 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);
}
cedrou
  • 2,780
  • 1
  • 18
  • 23
1

Sorry to see you had so many downvotes on this, I'm facing the same issue.

Sadly it doesn't seem to be possible - this MSDN page lists the only possible generic type constraints, and none can express the constraint "T and U can be any types, but must have distinct inheritance hierarchies" http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.80).aspx

We really need some kind of where T !: U or where T, U disjoint syntax; but as it stands there is no way to specify to the compiler that instances of TItem1 and TItem2 can never be substitutable for each other.

Tom Carver
  • 962
  • 7
  • 17
  • Yes, me too. Coming from the outerspace of all things possible, you'd need special language capabilities to name or identify the individual bases you might cast the object to, so they could be kept apart even when unifying. – Erik Eidt Sep 11 '12 at 00:29
-3

You could probably use this kind of implementation. You'll loose some generic 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)
    {
    }
}
Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • I don't understand your code here, you have interfaces with no {..} block, you have an interface which has method-implementations, you have more generic parameter constraints in IRoot than you have generic parameters, etc. You should loose the "probably" word, and make the code able to compile at the very least. – Lasse V. Karlsen Aug 17 '09 at 10:23
  • The "probably word" is because this solution is only feasible if there is a limited number of types possible as TM and if IRoot without all the generic arguments is acceptable. – Stefan Steinegger Aug 17 '09 at 12:19