Home > OS >  Generic interfaces and inheritance to call a generic method
Generic interfaces and inheritance to call a generic method

Time:05-10

I want to have a generic class which could call a method based on its generic type which is defined by a derived class. For that I implemented a base interface and a generic interface which has the base interface as generic and also derives from the base interface.

In the generic interface I want a method based on the type T of the base interface.

After that I wanted to implement a class based on the generic interface which should be able to call the generic method. This is the example code:

public interface BaseInterface
{ }

public interface GenericInterface<T> : BaseInterface where T : BaseInterface
{
    void Foo(T t);
}

public class C<T> : GenericInterface<T> where T : BaseInterface
{
    public C()
    {
        // None of these works
        Foo(this);
        Foo((T)this);
        Foo((BaseInterface)this);   
    }

    public void Foo(T t) { }
} 

Is there a way to achieve my desired behavior here?

The error message here is:

cannot convert from 'C<T>' to 'T'

which in my eyes should be possible because C derives from BaseInterface which is T

CodePudding user response:

While both C<T> and T need to derive from BaseInterface, that does not mean that then need to be the same. I might for example declare another type B : BaseInterface, and C<B>. So we would get the method Foo(B t) , it would obviously not be possible to call the method with this as the parameter, since C<B> is not B.

If you just need a method that needs a BaseInterface parameter, just declare it as Foo(BaseInterface t) instead. That way you could call it with this without any problem.

CodePudding user response:

It looks like you're looking for something like the Curiously Recurring Template Pattern for C#. In a simplified form it looks like this:

class Base<T>
{
    public void Foo(T t) { }
}

class C : Base<C>
{
    C()
    {
        Foo(this);
    }
}

In your case T is a type that derives from BaseInterface. Although C<T> also derives from BaseInterface it doesn't mean that you can bind a C<T> to T t. It's like trying to bind a string to a List, just because both implement IEnumerable. They are still different types.

For your full example it could look like this

public interface BaseInterface
{ }

public interface GenericInterface<T> : BaseInterface where T : BaseInterface
{
    void Foo(T t);
}

public class C<T> : GenericInterface<C<T>> where T : BaseInterface
{
    public C()
    {
        Foo(this);
    }

    public void Foo(C<T> t) { }
} 

CodePudding user response:

I Tried this, maybe can help you

public class C<T> : GenericInterface<T> where T : BaseInterface
{
    public C()
    {
        T t = default(T);
        BaseInterface bi;
        bi = t; // here can cast , bacuse T : BaseInterface , not BaseInterface : T
        t = bi;//here cast error , 
    }

    public void Foo(T t) { }
}

It's same like this case:

public class B { }
public class A : B
{
    public void CastTest()
    {
        A a = null;
        B b = null;
        b = a;
        a = b;//here error
    }
}

CodePudding user response:

Here's what you need for the Curiously Recurring Template in C#.

public interface BaseInterface { }
public interface GenericInterface<T> : BaseInterface where T : GenericInterface<T>
{
    void Foo(T t);
}

public abstract class C<T> : GenericInterface<T> where T : C<T>
{
    public abstract void Foo(T t);
}

Now you can go ahead and implement a real class:

public class D : C<D>
{
    public D()
    {
        Foo(this);
        Foo((D)this);
    }

    public override void Foo(D t) { }
}

That works fine.

However, calling Foo((BaseInterface)this); will never work in this code. It just doesn't make sense.

  •  Tags:  
  • c#
  • Related