I\'m writting a generalized method to use it in a special task at a T4 template. The method should allow me to use specialized types from a general interface. I thought abou
Maybe you're looking for this:
interface IGreatInterface<in U> where U : IAnInterface
{
Object aMethodAlpha(U parameter);
}
class SomeClass : IAnInterface { /*...*/ }
class GreatClass : IGreatInterface<SomeClass>
{
public Object aMethodAlpha(SomeClass parameter) {}
}
EDIT:
Yes, you are right: if you define a generic method in an interface, you can't implement that method with a concrete method using a compatible type.
How about using a delegate (since delegates support co- and contravariance):
[example deleted because I got the variance backwards -- it doesn't work.]
This question is quite confusing. Let me see if I can clarify it.
When I try to implement
IGreatInterface
the compiler flags an error foraMethodBeta()
because I've made that method using a subtype ofIAnInterface
I want to implement that method like this:Object aMethodBeta(AnInterestingClass parameter)
.
That's not legal. Simplifying somewhat:
class Food {}
class Fruit : Food {}
class Meat : Food {}
interface IEater
{
void Eat(Food food);
}
class Vegetarian : IEater
{
public void Eat(Fruit fruit);
}
Class Vegetarian
does not fulfill the contract of IEater
. You should be able to pass any Food to Eat, but a Vegetarian
only accepts Fruit. C# does not support virtual method formal parameter covariance because that is not typesafe.
Now, you might then say, how about this:
interface IFruitEater
{
void Eat(Fruit fruit);
}
class Omnivore : IFruitEater
{
public void Eat(Food food);
}
Now we have got type safety; Omnivore
can be used as an IFruitEater
because an Omnivore
can eat fruit, as well as any other food.
Unfortunately, C# does not support virtual method formal parameter type contravariance even though doing so is in theory typesafe. Few languages do support this.
Similarly, C# does not support virtual method return type variance either.
I'm not sure if that actually answered your question or not. Can you clarify the question?
UPDATE:
What about:
interface IEater
{
void Eat<T>(T t) where T : Food;
}
class Vegetarian : IEater
{
// I only want to eat fruit!
public void Eat<Fruit>(Fruit food) { }
}
Nope, that's not legal either. The contract of IEater
is that you will provide a method Eat<T>
that can take any T
that is a Food
. You cannot partially implement the contract, any more than you could do this:
interface IAdder
{
int Add(int x, int y);
}
class Adder : IAdder
{
// I only know how to add two!
public int Add(2, int y){ ... }
}
However, you can do this:
interface IEater<T> where T : Food
{
void Eat(T t);
}
class Vegetarian : IEater<Fruit>
{
public void Eat(Fruit fruit) { }
}
That is perfectly legal. However, you cannot do:
interface IEater<T> where T : Food
{
void Eat(T t);
}
class Omnivore : IEater<Fruit>
{
public void Eat(Food food) { }
}
Because again, C# does not support virtual method formal parameter contravariance or covariance.
Note that C# does support parametric polymorphism covariance when doing so is known to be typesafe. For example, this is legal:
IEnumerable<Fruit> fruit = whatever;
IEnumerable<Food> food = fruit;
A sequence of fruit may be used as a sequence of food. Or,
IComparable<Fruit> fruitComparer = whatever;
IComparable<Apples> appleComparer = fruitComparer;
If you have something that can compare any two fruits then it can compare any two apples.
However, this kind of covariance and contravariance is only legal when all of the following are true: (1) the variance is provably typesafe, (2) the author of the type added variance annotations indicating the desired co- and contra-variances, (3) the varying type arguments involved are all reference types, (4) the generic type is either a delegate or an interface.
If you want to inherit from a generic interface, see phoog's answer. If you are talking about trying to implement an interface co-variantly, that leads to my discussion below.
Assume:
internal interface IAnInterface { }
public class SomeSubClass : IAnInterface { }
public class AnotherSubClass : IAnInterface { }
public GreatClass : IGreatInterface { ... }
The problem with trying to implement the interface with a more derived (co-variant) argument is there's no guarante when this is called through an interface that an IAnInterface
passed in will be a SomeSubClass
instance. This is why it's not allowed directly.
IGreatInterface x = new GreatClass();
x.aMethodBeta(new AnotherSubClass());
IF You could do covariance, this would fail because you would be expecting a SomeSubClass
but would get a AnotherSubClass
.
What you could do is to do explicit interface implementation:
class GreatInterface : IGreatInterface
{
// explicitly implement aMethodBeta() when called from interface reference
object IGreatInterface.aMethodBeta(IAnInterface parameter)
{
// do whatever you'd do on IAnInterface itself...
var newParam = parameter as SomeSubClass;
if (newParam != null)
{
aMethodBeta(newParam);
}
// otherwise do some other action...
}
// This version is visible from the class reference itself and has the
// sub-class parameter
public object aMethodBeta(SomeSubClass parameter)
{
// do whatever
}
}
Thus, if you did this, your interface supports the generic, the class has a more specific method, but still supports the interface. The main difference is you'd need to handle the case where an unexpected implementation of IAnInterface
is passed in.
UPDATE: it sounds like you want something like this:
public interface ISomeInterface
{
void SomeMethod<A>(A someArgument);
}
public class SomeClass : ISomeInterface
{
public void SomeMethod<TA>(TA someArgument) where TA : SomeClass
{
}
}
This is not allowed, when you implement a generic method from an interface, the constraints must match.