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.