tags:

views:

247

answers:

5
public class BinarySearchTree<T>
where T : IComparable<T>
{
    public static BinarySearchTree<char> InitializeSampleCharacterBST()
    {
        var bst = new BinarySearchTree<char>();

        bst.Insert('F');
        bst.Insert('B');
        bst.Insert('A');
        bst.Insert('D');
        bst.Insert('C');
        bst.Insert('G');
        bst.Insert('I');
        bst.Insert('H');

        return bst;
    }

class Program
{
        static void Main(string[] args)
        {
            var bst = BinarySearchTree.InitializeSampleCharacterBST();
        }
}

Why is this illegal? It's expecting me to provide a type parameter to the method call for the class which makes no sense. A generic class or method has no use for a type parameter in a static context.

It wants me to write the call like this:

var bst = BinarySearchTree<foo>.InitializeSampleCharacterBST();

Where foo can be any type I want regardless of the fact that the static method call returns a specifically typed generic object.

+4  A: 

the class BinarySearchTree and BinarySeachTree<Foo> are completely separate; the language allows generic type overloading. Perhaps declare this method on a non-generic twin class:

public static class BinarySearchTree {
    public static BinarySearchTree<char> InitializeSampleCharacterBST() {...}
}
public class BinarySearchTree<T> {...} // rest of the code

Otherwise... what T would it use? And what if the static method talked to static fields? Let alone which T to use, each T gets different static fields (i.e. SomeType<Foo> has separate fields to SomeType<Bar>).

Marc Gravell
This is the only coherent explanation that I think can be provided for this problem -- a generic class with static fields has a different set of static fields for every distinct type.It has nothing to do with my issue, but explains why it would be disallowed. However, what if you want static fields to be shared across all T?
Then you'd put those fields in a non-generic type (such as BinarySearchTree above), perhaps using an `internal` modifier on a property/field to access them from the generic type.
Marc Gravell
For info, Earwicker and Jon also gave perfectly good (but different) reasons for disallowing it; the method could legitimately make use of `T` in the method... it is only a coincidence that **your** method *doesn't* use `T` directly.
Marc Gravell
+1  A: 

If you have a method that doesn't use a generic type, why make it a part of a generic class?

shahkalpesh
It's a factory method. There are plenty of instance methods on the class that take advantage of the generic type. Sure, I can make a non-generic duplicate named class that has all of the static factory methods.
A: 

Because the type itself is Generic, you have to provide a type argument, even if the static method you are interested in does not make use of that type argument. Its just the nature of generics in C#...they don't exist in a non-generic form at any time. If they did, that would cause conflicts with a non-generic version of the same type. You could try just doing the following, however I am not certain it would work (I've never tested it):

var bst = BinarySearchTree<>.InitializeSampleCharactersBST();
jrista
No, it won't. The only valid use of `SomeType<>` is in a `typeof(...)`, to get the open generic type. And you can't invoke methods on an open generic type...
Marc Gravell
I figured as much...I wasn't at a computer at the time to test that out.
jrista
+3  A: 

You're forgetting that type parameters don't only appear in the parameter/return type of a method. They can also appear in the implementation:

public static BinarySearchTree<char> InitializeSampleCharacterBST()
{
    var forSomeReason = new T();

By placing your method inside a static class with a type parameter, you are saying that the implementation of the method may (now or in some future revision) depend upon that type parameter.

If this isn't the case, you've put the method in the wrong place.

Daniel Earwicker
+1  A: 

As Marc said, it's sometimes useful to overload the type to have a non-generic class - and it would be in this case.

As for why it's necessary, suppose that the static method were actually implemented as:

public static BinarySearchTree<char> InitializeSampleCharacterBST()
{
    Console.WriteLine(typeof(T));
    return null;
}

That would be perfectly valid code - it's in a generic type, so it should have access to the type parameter... but you're trying to call the method without providing a generic type parameter, so it couldn't possibly work. In your case you happen to not use T anywhere within the method, but that's a coincidence. It's a bit like having an instance method which doesn't use this: you're not using the instance, but you still can't call it as if it were a static method.

As well as having separate static classes, another design technique which can be useful is to split your type into non-generic and generic pieces. That way, in cases where it can be awkward to work out which exact type you have, you don't actually need to know it in order to call some of the members. For example, a collection interface hierarchy might have:

public interface ISomeCollection
{
    int Count { get; }
    void Clear();
}

public interface ISomeCollection<T> : ISomeCollection
{
    void Add(T item);
}

I've used this technique myself for my Protocol Buffers port to C#, and it's proved very useful (if somewhat complicated).

Jon Skeet
This gets me thinking about the runtime implementation. This means that there must be a static class for all T for any generic class that carries a static field or method. Obviously this is impossible. I guess the runtime adds a concrete closed class when it encounters a new type usage for the generic class?
Yes. Basically you treat each concrete type as a different type, and it gets its own static variables, the type initializer is run separately for it etc. For value types, each type will also JIT the methods separately too. Native code is shared for reference types though.
Jon Skeet