0

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?

6
  • 3
    Have you tried it? Your interface doesn't even compile, it's unclear what it is you're asking here. Commented Mar 5 at 11:24
  • @ZoharPeled sorry, was typing from phone. Fixed interface and implementation (to some extent). Commented Mar 5 at 11:29
  • 1
    Well, your Process-function doesn't really do anything with the provided container, so it's hard to indicate what it's supposed to do and how the generic argument should be used. Commented Mar 5 at 11:37
  • @MakePeaceGreatAgain true. This is simplified example from test related code. It literally should return new object for test (please, don't ask why). Commented Mar 5 at 11:49
  • You have to implement the generic method, but you could do so explicitly, hiding the method from consumers that know your concrete type. Plus you can throw if people try to use it with the wrong types. Can you describe why this interface method exists like this at all? What is the original intention for how it should be implemented? Commented Mar 5 at 12:14

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

ConcreteOutType ment to replace TOut so they have a relation. Can you please elaborate on covariance and contravariance?
@IhorMarenych as long as ConcreteOutType has no inheritance-relation to whatever TOut is, there's no point in talking about co-variance and contra-variance, that only work on Generic<Derived> and Generic<Base>. So from your current design of IFoo these won't help you at all.
1

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 { }

2 Comments

Yep, I have tried this. My issue is this class used as a generic type in another class. public class SomeOtherClass<TClass, TOut, TIn> where TClass : IFoo<TOut, TIn> And due to this restriction I can't use Foo<TIn> as a generic parameter.
@IhorMarenych not sure I completely understand but you can do this: public class SomeOtherClass<TClass, TOut, TIn> where TClass : IFoo<TOut, TIn> where TOut : class where TIn : class { } and var someOtherClass = new SomeOtherClass<Foo<string>,ConcreteOutType,string>();
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.