So, I'm sure this has been answered somewhere out there before, but I couldn't find it anywhere. Hoping some generics guru can help.
public interface IAnimal{}
public class Orangutan:IAnimal{}
public void ValidateUsing<T>(Action<T> action) where T : IAnimal
{
Orangutan orangutan = new Orangutan();
action(orangutan); //Compile error 1
//This doesn't work either:
IAnimal animal = new Orangutan();
action(animal); //Compile error 2
}
- Argument type 'Orangutan' is not assignable to parameter type 'T'
- Argument type 'IAnimal' is not assignable to parameter type 'T'
Edit: Based on Yuriy and other's suggestions, I could do some casting such as:
public void ValidateUsing<T>(Action<T> action) where T : IAnimal
{
Orangutan orangutan = new Orangutan();
action((T)(IAnimal)orangutan);
//This doesn't work either:
IAnimal animal = new Orangutan();
action((T)animal);
}
The thing I wanted to do was call the ValidateUsing method like this:
ValidateUsing(Foo);
Unfortunately, if foo looks like this:
private void Foo(Orangutan obj)
{
//Do something
}
I have to explicitly specify the type when I call ValidateUsing
ValidateUsing<Orangutan>(Foo);
Why are you instantiating an Orangutan
if you are supposed to be accepting any IAnimal
?
public void ValidateUsing<T>(Action<T> action) where T : IAnimal, new()
{
T animal = new T();
action(animal); //Compile error 2
If you reuse your generic parameter, you won't have any type issues...
Now, with regard to why your code doesn't work, all that you're saying is that the type T
will derive from IAnimal
. However, it could just as easily be a Giraffe
as an Orangutan
, so you can't just assign an Orangutan
or IAnimal
to a parameter of type T
.
The thing is, that T represents some type which by the way implements IAnimal.
So, when you try to compile action(new Organatum())
you getting an error because you have declared that the action should take a parameter of type T
which in its turn could be of type, let's say, Fish
- you can't cast Organatum
to a Fish
, can you?
If you want to trigger any action which takes parameter of a type which implements IAnimal
interface, then simply forget about generics and use Action<IAnimal>
.
HTH.
Make the following changes:
Orangutan orangutan = new Orangutan();
action((T)(IAnimal)orangutan);
IAnimal animal = new Orangutan();
action((T)animal);
Try this.
Orangutan orangutan = new Orangutan();
Action<IAnimal> castedAction = action as Action<IAnimal>;
castedAction(orangutan);
public interface IAnimal { }
public class Orangutan : IAnimal { }
public void ValidateUsing<T>(Action<T> action) where T : IAnimal
{
Orangutan orangutan = new Orangutan();
action((T)(orangutan as IAnimal)); // needs to be cast as IAnimal
//This doesn't work either:
IAnimal animal = new Orangutan();
action((T)animal); // needs to be cast as T
}
It also seems like the fact that it's an interface makes a difference. If you had an abstract class Animal, instead of an interface, you could do this:
public abstract class Animal { }
public class Orangutan : Animal { }
public void ValidateUsing<T>(Action<T> action) where T : Animal
{
Orangutan orangutan = new Orangutan();
action(orangutan as T);
//This doesn't work either:
Animal animal = new Orangutan();
action(animal as T);
}