Ihor Marenych
Ihor Marenych

Reputation: 61

Generic method in non generic interface

Here is my interface.

public interface IFoo 
{
    TOut Process<TOut, TIn>(SomeClass<TOut, TIn> container)
        where TOut : class,
        where TIn : class;
}

I would like to achieve following results:

public class Foo<TIn> : IFoo
    where TIn : class
{
    public ConcreteOutType ConcreteOut { get; set; } = new();

    public ConcreteOutType Process<ConcreteOutType, TIn>(SomeClass<ConcreteOutType, TIn> container)
        => ConcreteOut;
}

My class does not implement interface. Is it even possible to swap generic type with concrete type in my implementation and respect interface method signature?

Upvotes: 0

Views: 90

Answers (3)

Ivan Petrov
Ivan Petrov

Reputation: 4987

Is it even possible to swap generic type with concrete type in my implementation and respect interface method signature?

No, but something similar could work if you are willing to make the interface generic:

interface IFoo<TOut, TIn>
where TOut : class
where TIn : class 
{
    TOut Process(SomeClass<TOut, TIn> container);
}

public class Foo<TIn> : IFoo<ConcreteOutType, TIn>
    where TIn : class {
    public ConcreteOutType ConcreteOut { get; set; } = new();

    public ConcreteOutType Process(SomeClass<ConcreteOutType, TIn> container)
    => ConcreteOut;
}

public class SomeClass<A, B> { }
public class ConcreteOutType { }

/FAD

Upvotes: 1

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37123

No, you can't do that. This is because you need to provide the exact same signature in your implementing class as in your interface. So when your interface-function defines a generic argument, your implementation needs to supply the excact same arguments. (There is something called co-variance and contra-variance. However this only applies if your ConcreteType has some relation to your TOut-argument from the interface, which it doesn't seem to have).

See this example to understand this:

interface IMyInterface { void DoSomething(object o); }
class M : IMyInterface { void DoSomething(MyType m) { ... } }

Now somewhere else you use an instance of that class via its interface:

IMyInterface i = // get an instance of the interface
i.DoSomething(...) // no notion of MyType here, we could provide any arbitrary object

You see we have no idea if the actual instance of i is of type M or whatever, and thus, that we need tp apply an instance of type MyType to the function. We only know the interface. So even if you could provide a more concrete signature in the implementation, there's no way to use it from the interface, as it has no knowledge of the concrete type MyType.

Upvotes: 2

Lajos Arpad
Lajos Arpad

Reputation: 77030

Your interface is generic. A concrete implementation assumes that the generic type is of a certain kind. This is diametrically opposed to the declared intent inside the interface.

Of course you can overload any method inside the implementation and you could have concrete types in the overloaded implementations, but you will also need a generic implementation to guarantee that it fulfills the requirement. Example:

using System;

public interface IFoo<TIn, TOut>
{
    public TOut Process(System.Collections.Generic.SortedDictionary<TOut, TIn> container);
}

public class Foo<TIn, TOut> : IFoo<TIn, TOut>
{
    public int Process(System.Collections.Generic.SortedDictionary<String, TIn> container) {
        return -4;
    }
    public TOut Process(System.Collections.Generic.SortedDictionary<TOut, TIn> container) {
        return default!;
    }
        
    public Foo() {
    
    }
}

public class Program
{
    public static void Main()
    {
        Foo<String, String> foo = new Foo<String, String>();
        Console.WriteLine(foo.Process(new System.Collections.Generic.SortedDictionary<String, String>()));

    }
}

This returns -4.

Upvotes: 1

Related Questions