2

I have a specific problem where I have an interface IA that has a method Foo that returns another interface IB. I want to be able to have two interfaces IA1 (that implements IA) and IB1 (that implements IB), and have IA.Foo return IB1. I'd like for this to happen with any other interface that implements IA (for example, some IA2).

I think the only possible way to do this is via higher-order-types, which would look like the "solution" below (which is not valid C#):

public interface IA<M> where M<> : IB<>
{
    M<T> Foo1<T>(T val);
    M<T> Foo2<T>();
}

public interface IB<T>
{
    T Bar();
}

public interface IA1 : IA<IB1> {}

public interface IB1<T> : IB<T>
{
    void Bar1();
}

public interface IA2 : IA<IB2> {}

public interface IB2<T> : IB<T>
{
    void Bar2(T val);
}

public void MyFunc()
{
    IA1 myA1 = GetMyA1();
    IB1<int> myB1Int = myA1.Foo1<int>(2);
    int myB1IntBar = myB1Int.Bar();
    myB1Int.Bar1();
    IB1<string> myB1String = myA1.Foo2<string>();
    string myB1StringBar = myB1String.Bar();

    IA2 myA2 = GetMyA2();
    IB2<string> myB2 = myA2.Foo1<string>("Hello World");
    string myB2StringBar = myB2.Bar();
    myB2.Bar2("Value");
}

Is there a way to simulate this in C#?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
gonzaw
  • 771
  • 4
  • 17

1 Answers1

4

I think that what you're looking for is the concept of Covariance. You can find some explanations online for it. I'll point you to some .NET documentation, which I think are relevant to this question but that on their own may not be the best for explaining the concept of covariance.

How to define an interface with a covariant type parameter

A covariant type parameter is marked with the out keyword (Out keyword in Visual Basic, + for the MSIL Assembler). You can use a covariant type parameter as the return value of a method that belongs to an interface, or as the return type of a delegate.

The out keyword on generic type parameters

An interface that has a covariant type parameter enables its methods to return more derived types than those specified by the type parameter.

I've revised your code using the out keyword. Take a look and see if this is what you had in mind:

public interface IA<T, out M> where M : IB<T>
{
    M Foo(T val);
}

public interface IB<T>
{
    void Bar();
}

public interface IA1<T> : IA<T, IB1<T>> {}

public interface IB1<T> : IB<T>
{
    void Bar1();
}

public interface IA2<T> : IA<T, IB2<T>> {}

public interface IB2<T> : IB<T>
{
    void Bar2();
}

public void MyFunc()
{
    IA1<int> myA1 = GetMyA1();
    IB1<int> myB1 = myA1.Foo(2);
    myB1.Bar();
    myB1.Bar1();

    IA2<string> myA2 = GetMyA2();
    IB2<string> myB2 = myA2.Foo("Hello World");
    myB2.Bar();
    myB2.Bar2();
}
Dr. Wily's Apprentice
  • 10,212
  • 1
  • 25
  • 27
  • Hi. Thanks for the response, but the variable `T` is not a parameter of `IA`, but of `Foo` instead (and indeed, it actually has several other methods like `Foo` with other type parameters). I'll update the question to show it more clearly – gonzaw Mar 12 '16 at 00:25
  • @gonzaw I get what you're trying to do, but I don't *think* it's syntactically possible in C#. I think that you need to provide type parameters for the generic types within a "where" type constraint. It might be that the approach can be refactored to better achieve what you really want, though. – Dr. Wily's Apprentice Mar 12 '16 at 00:46