Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a generic parameter that isn't generic

Tags:

c#

generics

I have an interface with two generic parameters, but one of the parameters is expected to be provided by the class implementation.

public interface IA<T, U> { ... }
public class X<T> : IA<T, int> { ... }
public class Y<T> : IA<T, MyClass> { ... }

However, another interface have a method that takes an instance of IA as a parameter - however, every instance must be the same (the same class can take multiples X, but then it will never take a Y, or vice-versa). I tried to put it as a generic constrainst, but then I have something like

public interface IB<T, U, V> where U : IA<T, V> {
   void MyMethod(U value);
}
public class Z<T> : IB<T, X<T>, int> { ... }

Of course, I don't want to write that parameter V, as I can't choose a value for it. The parameter U already dictates what the value of V should be! However, I can't simply remove V, because then I couldn't write the constraint.


Another solution is to not use the constraint:

public interface IB<T> {
   void MyMethod(IA<T> value);
}

But this way, I can't ensure the implementation of IB will receive only one implementation of IA (ie. it will be able to receive both X and Y, and it should not).


Is there any way to avoid the creation of the generic parameter V in the interface IB (in the first solution) while still mutually-excluding the implementations of IA? Is there any specific reason the compiler can't infer the type of V and allow me to write only class Z<T> : IB<T, X<T>> or this case just wasn't expected in the language specs/was chosen to not be implemented?

like image 337
Mephy Avatar asked Jul 15 '14 01:07

Mephy


1 Answers

You already have enough generic types to restrict IB<T,U>.MyMethod() from receiving both X and Y. You just need to define the method argument as accepting on a specific type.

    public interface IA<T,U> {}
    public class X<T> : IA<T,int> {}
    public class Y<T> : IA<T,string> {}

    public interface IB<T,U>
    {
        void MyMethod(IA<T,U> value);
    }

    IB<int,int> foo;
    X<int> a;
    Y<int> b;

    foo.MyMethod(a); // will compile
    foo.MyMethod(b); // will not compile

Is there any way to avoid the creation of the generic parameter V in the interface IB (in the first solution) while still mutually-excluding the implementations of IA? Is there any specific reason the compiler can't infer the type of V and allow me to write only class Z : IB> or this case just wasn't expected in the language specs/was chosen to not be implemented?

I don't think that's how inference works in C#. To infer the type for U the MyMethod would be written like this.

    public interface IB<T>
    {
        void MyMethod<U>(IA<T,U> value);
    }

    IB<int> foo = null;
    X<int> a;
    foo.MyMethod(a); // int type is inferred by compiler

You still have to use IA<T,U> in your IB interface. I don't think there is an easy way around that.

like image 56
Reactgular Avatar answered Oct 05 '22 04:10

Reactgular