I'm using C#.NET 3.5. I get
argument type 'GenericTest.BarkStrategy' is not assignible to parameter type 'GenericsTest.IAnimalStrategy'
with the following (for this question as much simplified as possible) code:
using System.Collections.Generic;
namespace GenericsTest {
class Program {
static void Main(string[] args) {
List<IAnimalStrategy<IAnimal>> strategies =
new List<IAnimalStrategy<IAnimal>>();
strategies.Add(new BarkStrategy());
}
}
interface IAnimal { }
interface IAnimalStrategy<T> where T : IAnimal { }
class Dog : IAnimal { }
class BarkStrategy : IAnimalStrategy<Dog> { }
}
The error "Argument of type is not assignable to parameter of type 'never'" occurs when we declare an empty array without explicitly typing it and attempt to add elements to it. To solve the error, explicitly type the empty array, e.g. const arr: string[] = []; .
The generic argument list is a comma-separated list of type arguments. A type argument is the name of an actual concrete type that replaces a corresponding type parameter in the generic parameter clause of a generic type. The result is a specialized version of that generic type.
You have to tell the compiler that your interface is covariant : IAnimalStrategy<out T>
namespace GenericsTest
{
class Program
{
static void Main(string[] args)
{
List<IAnimalStrategy<IAnimal>> strategies = new List<IAnimalStrategy<IAnimal>>();
strategies.Add(new BarkStrategy());
}
}
interface IAnimal { }
interface IAnimalStrategy<out T> where T : IAnimal { }
class Dog : IAnimal { }
class BarkStrategy : IAnimalStrategy<Dog> { }
}
Unfortunately, it is available only in C# 4.0 : How is Generic Covariance & Contra-variance Implemented in C# 4.0?
For understanding the problem, you can forget the list, this line doesn't compile :
IAnimalStrategy<IAnimal> s = new BarkStrategy();
The IAnimalStrategy<IAnimal>
interface can do things on IAnimal, maybe set a property of type IAnimal
interface IAnimalStrategy<T> where T : IAnimal
{
T Animal {get; set;}
}
Then you would be able to do something like
IAnimalStrategy<IAnimal> s = new BarkStrategy();
s.Animal = new Cat();
It will blow in your face. So C#3.5 doesn't allow you to do that.
C#4.0 will allow you to that, if you said that T is covariant with the out
keyword
interface IAnimalStrategy<out T> where T : IAnimal
{
T Animal {get; set;}
}
This will blow again,
Invalid variance: The type parameter 'T' must be invariantly valid on IAnimalStrategy.Animal'. 'T' is covariant.
Covariance and Contravariance are difficults to understand, I suggest you read the awesome series on Eric Lippert's Blog : Covariance and Contravariance in C#
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