Is There a Reasonable Approach to "Default" Type Parameters in C# Generics

Is there a reasonable approach to default type parameters in C# Generics?

Subclassing is the best option.

I would subclass your main generic class:

class BaseGeneric<T,U>

with a specific class

class MyGeneric<T> : BaseGeneric<T, string>

This makes it easy to keep your logic in one place (the base class), but also easy to provide both usage options. Depending on the class, there is probably very little extra work needed to make this happen.

Anyway to default a generic parameter to a certain type?

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>.

How do you provide a default type for generics?

You can't do it in the definition of the class:

var foo = new MyGenericClass(); // defaults to integer... this doesn't work
var bar = new MyGenericClass<MyEnum>(); // T is a MyEnum

If really value the implicitness of the default type being int, you'll have to do it with a static factory method, although I don't see the value of it.

public class MyGenericClass<T>
{
public static MyGenericClass<T> Create()
{
return new MyGenericClass<T>();
}
public static MyGenericClass<int> CreateDefault()
{
return new MyGenericClass<int>();
}
}

See below for how you really don't benefit from the above.

var foo = MyGenericClass<MyEnum>.Create();
var bar1 = MyGenericClass.CreateDefault(); // doesn't work
var bar2 = MyGenericClass<int>.CreateDefault(); // works, but what's the point

If you want to take it even farther, you can create a static factory class that will solve this, but that's an even more ridiculous solution if you're doing it for no other reason than to provide a default type:

public static class MyGenericClassFactory
{
public static MyGenericClass<T> Create<T>()
{
return new MyGenericClass<T>();
}
public static MyGenericClass<int> Create()
{
return new MyGenericClass<int>();
}
}

var foo = MyGenericClassFactory.Create(); // now we have an int definition
var bar = MyGenericClassFactory.Create<MyEnum>();

Default for generic type?

No. There is no option for default types on generic types in C#.

Your second example is often the "best" option available, if you need this behavior.

Default type for generics in C#. SO claims this is not possible, and yet it would appear that EventHandler exhibits this behavior?

No. That's not a 'default' value. EventHandler and EventHandler<T> are completely different types. Same thing goes for IEnumerable and IEnumerable<T> and all the other similarly named types that exhibit this pattern.

You can roll your own version of this pretty easily.

class MyType
{
void Foo(object obj) ...
}

class MyType<T> : MyType
{
void Foo(T obj)
{
base.Foo(obj);
}
}

Can I make a generic optional, defaulting to a certain class?

I don't think there's much you can do about it, to be honest. You could make Foo doubly generic:

public class Foo<TData, TArgs> where TArgs : FooEventArgs<TData>
{
public delegate void EventHandler<TArgs>(object sender, TArgs e);
public event EventHandler<TArgs> Changed;
}

Then you could write:

public class Foo : Foo<object, FooEventArgs>

... but it's really making things very complicated for very little benefit.

I would also say that even though it's a bit more verbose to include the type argument, it does make it very clear - whereas inheritance can muddy the waters in various ways. I'd steer clear of class inheritance when you're not really trying to model behaviour specialization.

The reason your implicit conversion doesn't work has nothing to do with generics, by the way - as the error message states, you can't declare a conversion (implicit or explicit) which goes up or down the inheritance hierarchy. From the C# spec section 6.4.1:

C# permits only certain user-defined conversions to be declared. In particular, it is not possible to redefine an already existing implicit or explicit conversion.

(See that section for more details.)


As a side note, I find it more common to use inheritance the other way round for generics, typically with interfaces:

public interface IFoo
{
// Members which don't depend on the type parameter
}

public interface IFoo<T> : IFoo
{
// Members which all use T
}

That way code can receive just an IFoo without worrying about the generics side of things if they don't need to know T.

Unfortunately, that doesn't help you in your specific case.

What about optional generic type parameters in C# 5.0?

I am definitely for it.

I'm currently writing helper methods for different scenarios where I want to pass references to different members and methods of classes. To accomplish this I'm taking, for example, an Expression<Func<TIn, TOut>> as argument to the helper (that lets me reach the method with a lambda expression, thus keeping everything strongly typed).

BUT - I currently need to define a new helper method for each different number of input arguments, since I need to have a different amount of generic arguments to it. Instead of

HelperMethod<TIn>(Expression<Action<TIn>> arg) // Yes, C# can distinguish
HelperMethod<TOut>(Expression<Func<TOut>> arg) // these two from eachother
HelperMethod<TIn, TOut>(Expression<Func<TIn, TOut>> arg)
HelperMethod<TIn1, TIn2, TOut>(Expression<Func<TIn1, TIn2, TOut>> arg)
// etc

I could make do with, at the most, two methods:

HelperMethod<TIn>(Expression<Action<TIn>> arg)
HelperMethod<TOut, TIn1 = DummyType, ...>(Expression<Func<TIn1, ..., TOut> arg)

In my case, it would avoid a lot of code duplication...

Custom default value for generic parameter

The Null method is statically bound to the object version. I think your simplest option is to use a switch, or a dictionary, to handle your special cases. Like this:

private static readonly Dictionary<Type, Object> _NullValues = new Dictionary<Type, Object>()
{
{ typeof(String), String.Empty }
};

public static object Null<T>(this T o)
{
object ret;
return _NullValues.TryGetValue(typeof(T), out ret)
? ret : default(T);
}

How to set a default type for T in a static generic method?

You can't specify a default type for T however you can simply overload the newStack method to get the behaviour you want. The overloaded method will automatically create a new stack of type int.

Your code would look something like this:

public static Stack<T> newStack<T>(int length)
{
Stack<T> s = new Stack<T>();
for (int i = 0; i < length; i++)
{
Console.WriteLine("print num");
string input = Console.ReadLine();
T value = (T)Convert.ChangeType(input, typeof(T));
s.Push(value);
}
return s;
}

public static Stack<int> newStack(int length)
{
// Call our original new stack method but pass
// integer as the type T
return newStack<int>(length);
}

Now you can call the second method if you just want to create a new stack of type integer like this:

newStack(5);

Otherwise you can create stacks of other types with:

newStack<string>(5);


Related Topics



Leave a reply



Submit