22

Is there a way to provide a default type for a parameter T of a generic, something like:

class Something<T = string>
{
}

I know there aren't many strong reasons for this, but I would like to hint the code client which type he should be preferably using.

Another thing, can I restrict the generic type to a ValueType? I've just seen that you can't, but still, I'd like to know why. Anyone has a clue?

Thanks!

7
  • This is not possible by default.
    – Vercas
    Commented Nov 8, 2010 at 20:54
  • 1
    Why are you saying you can't restrict a generic type to a value type when nearly every answer here demonstrates just how it's done? (Not via ValueType, but by using the struct keyword.) Commented Nov 8, 2010 at 21:13
  • @stakx I said by default. (Like he tried to - by "default"ing the value.)
    – Vercas
    Commented Nov 8, 2010 at 21:29
  • @Vercas, sorry for the misunderstanding, my comment was directed at the OP, not at your comment. Commented Nov 8, 2010 at 22:36
  • @stakx Oh, okay. By the way, Bruno, if my answer was good, why don't you click the accept icon? (the checkmark)
    – Vercas
    Commented Nov 9, 2010 at 19:33

5 Answers 5

33

Ok, I suppose you have the class:

class Something<T>
{

}

Now, you might want another class:

class Something : Something<string>
{
    // NO MORE CODE NEEDED HERE!
}

This is the only and the best way.
So if one uses Something he will actually use Something<string>.

7
  • 2
    This works (fsvo "works", not that I would recommend it generally) because Something and Something<'> (and Something<','> is different still) are two different classes (imagine the case of system.collections.IEnumerable and systems.collections.generic.IEnumerable<T> -- this differs from Java where there is essentially only one "collapsed" type allowed). On the other hand, now you have two different types :-)
    – user166390
    Commented Nov 8, 2010 at 21:04
  • Another alternative may be: using Something = foo.Something<String>; However the using construct is only available in a few cases (before classes or at top of an outer class before members, etc.) and isn't externally exposed as an type/alias.
    – user166390
    Commented Nov 8, 2010 at 21:12
  • @pst I'd use that instead of what I posted, but I thought he might need that way more.
    – Vercas
    Commented Nov 8, 2010 at 21:28
  • 2
    There are some problems with that approach though. Try casting a "Something<string>" to "Something". You either get a compilation error (if types are known), or a runtime exception (if type checking happens during runtime). That's because "Something" is different than "Something<string>" and actually the former is a subclass of the latter. Commented Dec 15, 2014 at 16:09
  • @Saysmaster Unless the cast is overloaded and it fully and reliably copies the identity of the original object.
    – Vercas
    Commented Dec 15, 2014 at 21:40
3

According to the docs you can constrain T to be a value type using the where keyword

where T: struct

Class declaration would then look like this:

class Something<T> where T: struct {
  ...
} 

Though string is not a value type and you won't be able to use it with such a constraint. Maybe IComparable would be better in case you want to also use the string type.

As for specifying the default type, I don't believe it is possible.

2

I don't believe there is a way to default it to a certain type, but you could put that as a comment in the XML docs. As far as restricting to a value type, you can obtain this behavior by declaring your generic as follows:

class MyGeneric<T> where T : struct
{
    ...
}
3
  • And +1 for answering the 2nd question :p
    – user166390
    Commented Nov 8, 2010 at 21:08
  • 1
    If you want strings, you might need where T : class because System.String is a class.
    – Vercas
    Commented Nov 8, 2010 at 21:31
  • @Vercas - correct or you will get the error: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Something<T>'
    – atconway
    Commented Jan 28, 2013 at 14:59
2

You can use the where keyword to constrain the specific types that can be used as type parameters.

For example, you could your class to only accept generic type parameters where the type implements the IComparable interface:

class Something<T> where T : IComparable
{
}

Or, as you mentioned, you can constrain T to be a value type by using where T : struct:

class Something<T> where T : struct
{
}

See MSDN's article on Constraints on Type Parameters for more info. Hope this helps!

0

You need a subclass. Recently I needed something like that, this is my solution:

    public abstract class MyGenericClass<T1, T2>
    {
        public abstract void Do(T1 param1, T2 param2);
    }

    public class Concrete : MyGenericClass<string, int?>
    {        
        public override void Do(string param1, int? param2 = null)
        {
            Console.WriteLine("param1: {0}", param1);

            if (param2 == null)
                Console.WriteLine("param2 == null");
            else
                Console.WriteLine("param2 = {0}", param2);

            Console.WriteLine("=============================================");
        }        
    }

You can call the method:

    string param1 = "Hello";
    Concrete c = new Concrete();
    c.Do(param1);
    c.Do(param1, 123);
    c.Do(param1, (int?)null);
    /*  Result:
    param1: Hello
    param2 == null
    =============================================
    param1: Hello
    param2 = 123
    =============================================
    param1: Hello
    param2 == null
    =============================================
    */

I prefer to use null default values since i read this: C# In Depth – Optional Parameters and Named Arguments

Not the answer you're looking for? Browse other questions tagged or ask your own question.