I have this desired class hierarchy:
interface IClass
{
string print(IClass item);
}
class MyClass : IClass
{
// invalid interface implementation
// parameter type should be IClass not MyClass
string print(MyClass item)
{ return item.ToString(); }
}
I tried to solve interface implementation problem by using generic types as next with no success:
interface IClass
{
string print<T>(T item) where T : IClass;
}
class MyClass : IClass
{
string print<T>(T item) where T : MyClass
{ return item.ToString(); }
}
What should I do?
Make your interface generic
interface IClass<T> where T : IClass<T>
{
string print(T item);
}
class MyClass : IClass<MyClass>
{
public string print(MyClass item)
{
return item.ToString();
}
}
It's helpful to understand why this is illegal. The feature you want is formal parameter type covariance, and very few languages offer it. (Eiffel, I think has this as a feature.) It is not often found in languages because it is not safe! Let me illustrate with an example:
class Animal {}
class Lion : Animal { public void Roar() { } }
class Giraffe : Animal { }
interface IFoo { void M(Animal a); }
class C : IFoo
{
public void M(Lion lion) { lion.Roar(); }
}
class P
{
public static void Main()
{
IFoo foo = new C();
foo.M(new Giraffe());
}
}
And we just made a giraffe roar.
If you look at all those type conversions, the only one that can sensibly be made illegal is matching C.M(Giraffe)
to IFoo.M(Animal)
.
Now, formal parameter type contravariance is typesafe but it is not legal in C# except in some very limited circumstances. If C# supported it, which it does not, then you could safely do something like this:
interface IBar { void M(Giraffe g); }
class D : IBar
{
public void M(Animal animal) { ... }
}
class P
{
public static void Main()
{
IBar bar = new D();
bar.M(new Giraffe());
}
}
See what happened there? IFoo.M says "I can take a giraffe", and C.M says "I can accept any giraffe because in fact I can accept any animal". That would be typesafe if C# supported it, but it only supports it in two ways:
An example of the first is that an expression of type IComparable<Animal>
may be assigned to a variable of type IComparable<Giraffe>
by the same logic: a method that compares two animals can be used where a method that compares two giraffes is needed. This was added in C# 4.
An example of the second is:
delegate void MyFunction(Giraffe g);
...
D d = new D();
MyFunction myfunc = d.M;
Again, we need a function that takes a Giraffe, and we supply one that takes any Animal. This feature was added in C# 2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With