Reputation: 4482
I've been playing with interfaces and generics.
What I want is an Foo<T>
to be a shorthand for Foo<T, int>
Is this sensible? Is the following an accepted way of doing it?
using System.Diagnostics;
namespace MyNamespace
{
public class Foo<T> : Foo<T, int> where T : class
{
}
public class Foo<T, U> where T : class
{
public void Bar()
{
Debug.WriteLine("this: " + GetType().Name + ", T: " + typeof(T).Name + ", U: " + typeof(U).Name);
}
}
class Program
{
static void Main(string[] args)
{
var fooT = new Foo<string>();
var fooTU = new Foo<string, int>();
fooT.Bar();
fooTU.Bar();
}
}
}
What my actual question is... is it possible to up (down?) cast from a Foo<T, int>
to a Foo<T>
where T
is the same type. Does it even make sense to say this, or is this something to do with co/contravariance (which still eludes me)?
To me, a somewhat ignorant human, in this example Foo<string>
and Foo<string, int>
are identical types, but of course ((Foo<string>) fooTU).Bar();
does not work!
Upvotes: 1
Views: 281
Reputation: 14477
in this example Foo and Foo are identical types
This is incorrect. Foo<T>
is a Foo<T,int>
, but Foo<T,int>
is not necessarily a Foo<T>
. This is why you can cast from Foo<T>
to Foo<T,int>
, but not vice-versa.
Upvotes: 1
Reputation: 152566
is it possible to up cast from a
Foo<T, int>
to aFoo<T>
where T is the same type.
Not safely - it's like casting from an Animal
to a Dog
- it might be a dog
, but if it's not you're going to get an exception at run-time.
You also cannot take a Foo<string, int>
and treat it like a Foo<string>
for the same reason.
Upvotes: 1
Reputation: 1501133
What my actual question is... is it possible to up (down?) cast from a
Foo<T, int>
to aFoo<T>
where T is the same type. Does it even make sense to say this, or is this something to do with co/contravariance (which still eludes me)?
You can cast from Foo<string, int>
to Foo<string>
if the actual object is of type Foo<T>
. The fact that they have the same name is completely irrelevant here, so let's change that:
class Foo<T, U> {}
class Bar<T> : Foo<T, int>
Now:
Foo<string, int> foo = new Foo<string, int>();
Bar<string> bar = (Bar<string>) foo; // Bang, throws
But:
Foo<string, int> foo = new Bar<string>();
Bar<string> bar = (Bar<string>) foo; // This is fine
The generics are pretty irrelevant here, really... it's the normal rules of casting.
Upvotes: 3