views:

566

answers:

3

I'm working in a C# web service with a generic static class that takes a type. I was wondering why this does not compile:

Type type1 = typeof(MySnazzyType);
Assert.AreEqual(0, ConnectionPool_Accessor<type1>._pool.Count);

It gives this error:

The type or namespace name 'type1' could not be found (are you missing a using directive or an assembly reference?)

And ReSharper, when I hover over type1 in that second line of code, says "Type or namespace name expected". Well, type1 is a type! It's a variable of type Type! It also doesn't work if I do:

Type type1 = typeof(MySnazzyType);
Assert.AreEqual(0, ConnectionPool_Accessor<typeof(type1)>._pool.Count);

I was hoping to assign my types to a couple of different Type variables and just use those in testing the different generic static classes, instead of typing out MySnazzyType each time. Any ideas, or am I stuck with doing:

Assert.AreEqual(0, ConnectionPool_Accessor<MySnazzyType>._pool.Count);

Edit: to clarify, MySnazzyType is not a generic class, nor does it inherit from a generic class. The only generic class here is ConnectionPool_Accessor.

Thanks to Pavel's comment "Essentially, your problem is that C# is a statically typed language", I now know that Ruby has spoiled me. ;)

+2  A: 

Generic types are evaluated at compile time, not in runtime. Since it cannot be determined at runtime time what type1 will be, this construct is not allowed.

This is actually what Resharper says: type1 is not a Type, it's a variable of the type Type, (just as it could be an object of the type String).

Fredrik Mörk
Er, did you swap what you meant to say? Maybe "Generic types are evaluated at _runtime_, not in _compile time_."
Sarah Vessels
Also, why is it unable to determine at compile type what `type1` will be, since it is written out to be `typeof(MySnazzyType)`?
Sarah Vessels
No, he wrote it correctly. Generic type in your case is `ConnectionPool_Accessor<>`, and it is indeed resolved at compile time. And at that point there's no way of telling what type will `type1` resolve to. Essentially, your problem is that C# is a statically typed language.
Pavel Minaev
To repeat: `type1` is a _variable_ of type "reference to `System.Type`. The latter is not a type! It's a _class_, instances of which _describe_ a type.
Pavel Minaev
@Sarah: it was the other occurence of the term *compile time* that was wrong. Corrected that. Regarding why it can't figure out what `type1` will be, I guess the compiler doesn't go that far. Even if it did, `type1` would still be a variable, not a type.
Fredrik Mörk
+3  A: 

First of all, ReSharper is actually correct. It isn't a type, it's a variable. Granted, it's a variable that is holding the reflection object that corresponds to a type, but that isn't enough.

Between the <...> brackets, you have to write the name of a type, not the name of any other identifier.

You can construct generic objects through reflection, however, and access their properties, even static ones, so you should be able to rewrite the code to do that, however, have you looked at NUnit 2.5?

From the latest release notes, it appears that unit test classes can now be generic, and you can specify with an attribute on the test class which types to test it with.

This would allow you to write something like this (note, I have not tested this, I only looked up the names of the new attributes in the documentation):

[TestFixture(typeof(MySnazzyType))]
[TestFixture(typeof(MyOtherSnazzyType))]
public class Tests<T>
{
    [Test]
    public void PoolCount_IsZero()
    {
        Assert.AreEqual(0, ConnectionPool_Accessor<T>._pool.Count);
    }
}
Lasse V. Karlsen
A: 

The TestFixture attribute should set you up, but just for the heck of it: if you wanted to do all this at runtime, you could do so using reflection.

Type poolType = typeof(ConnectionPool_Accessor<>);
Type snazzyType = typeof(MySnazzyType); // Or however you want to get the appropriate Type
poolType.MakeGenericType(snazzyType);

You could then proceed to do whatever you want using reflection on poolType. Of course, that will be a major pain in the butt unless you use C# 4.0 dynamic typing.

Thorarin