tags:

views:

376

answers:

6

A colleague pointed me to a strange case in C# (not so sure if this actually strange though).
Suppose you have a class Employee. If you want to create a Generic List<> of type Employee, you can simply do:

List<Employee> x = new List<Employee>;

I understand that I need to pass the Employee type to the Generic list so that it knows the required type information about Employee and generates methods that return and accept parameters that are compatible with Employee.

Now my question is, why isn't it possible to do the following?

Employee x = new Employee();
List<typeof(x)> list = new List<typeof(x)>();

Shouldn't this suffice the information required for List<> to know, in order to create a list? In other words, the type of x which is the type of Employee is now passed as a generic type parameter to List<>, which (as I used to believe) is the same as passing list the type name (in this case Employee).

I know that something like this is available in Java (using the .class) keyword on a variable.

I'm sure I AM missing something, so please, enlight me guys!

+31  A: 

No, the equivalent of that isn't available in Java. You can't use "x.class" to get at the declared type of a variable.

Moreover, typeof(x) doesn't work in C# either to get the type of a variable - it returns a Type reference for the type name, e.g. typeof(string) will return a reference to the Type object associated with the System.String type. That's equivalent to using String.class in Java. (Note that again, that's applying .class to a type name, not a variable name.)

Java generics don't support anything like your final statement either. If you believe they do, please give a sample :)

What you can do in C# is use type inference to do what you want:

public static List<T> CreateListForSampleType<T>(T sample)
{
    return new List<T>();
}

...

Employee x = new Employee();
var list = CreateListForSampleType(x);

Note that there's no reason why C# couldn't be extended to allow something like typeof(variablename) or List<typeof(variablename)> - it's all compile-time type information, after all. However, I can't see that it would meet the team's requirements for usefulness... there are other far more useful features I'd like to see first :)

Jon Skeet
Good code example. What would happen if you used `typeof` on the `list` variable?
FrustratedWithFormsDesigner
typeof(list) would result in compilation error.
Michał Piaskowski
Jon, thank you for your detailed answer! And since this is compile time information, then I'm on the right track. Speaking about whether it's useful or not is somewhat controversial though ;).
Galilyou
While I do use the pattern Jon describes here, I do not like it. I would much prefer to be able to do what the OP was trying. When I initially discovered that I had to pass an example object, I was saddened.
Brett Widmeier
+2  A: 

The reason for this is that typeof() returns a type object, while you need a type name to initialize a list at compile-time.

Håvard S
+1  A: 

typeof is used with class names. Use GetType() on an object, but only at runtime...

Daren Thomas
+2  A: 

One part of the answer is that the type of x is not available at compile time, i.e. it might be created using something like this:

Employee x = EmployeeFactory.NewEmployee("John Doe"); // Returns TraineeEmployee, Employee or ManagementEmployee;

List<typeof(x)> l = new List<typeof(x)> l(); // What type is it?

You can however create a List of a base class of what you want to store in the list (or even a List of "object"s).

dbemerlin
+1  A: 

What you are missing - imho - is the difference between a static type reference at compile-time and a dinamyc type reference (via an instance of System.Type) at run-time.

typeof() and .GetType() give you the latter. (for types and instances, respectively)

I hope it makes clear.

Jon Skeet's code above is cool.

Dercsár
A: 

Can't find a reason to create an empty list since C# 3.0.

I generally create list instances only with a ToList method from an IEnumerable, which is in turn generated using a yield return, Concat(), Repeat(), Where() etc.

var list = CreateEmployees().ToList();

,

public IEnumerable<Employee> CreateEmployees()
{
 yield return new Employee("Foo");
 yield return new Employee("Bar");
}
George Polevoy