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

C#GenericsTypesDefaultParameters

C# Problem Overview


In C++ templates, one can specify that a certain type parameter is a default. I.e. unless explicitly specified, it will use type T.

Can this be done or approximated in C#?

I'm looking for something like:

public class MyTemplate<T1, T2=string> {}

So that an instance of the type that doesn't explicitly specify T2:

MyTemplate<int> t = new MyTemplate<int>();

Would be essentially:

MyTemplate<int, string> t = new MyTemplate<int, string>();

Ultimately I am looking at a case wherein there is a template that is fairly widely used, but I am considering expanding with an additional type parameter. I could subclass, I guess, but I was curious if there were other options in this vein.

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

One solution is subclassing. Another one I would use instead, is factory methods (combined with var keyword).

public class MyTemplate<T1,T2>
{
     public MyTemplate(..args..) { ... } // constructor
}

public static class MyTemplate{

     public static MyTemplate<T1,T2> Create<T1,T2>(..args..)
     {
         return new MyTemplate<T1, T2>(... params ...);
     }

     public static MyTemplate<T1, string> Create<T1>(...args...)
     {
         return new MyTemplate<T1, string>(... params ...);
     }
}

var val1 = MyTemplate.Create<int,decimal>();
var val2 = MyTemplate.Create<int>();

In the above example val2 is of type MyTemplate<int,string> and not a type derived from it.

A type class MyStringTemplate<T>:MyTemplate<T,string> is not the same type as MyTemplate<T,string>. This could pose some problems in certain scenarios. For instance you can't cast an instance of MyTemplate<T,string> to MyStringTemplate<T>.

Solution 3 - C#

you can also create a class Overload like so

public class MyTemplate<T1, T2> {
    public T1 Prop1 { get; set; }
    public T2 Prop2 { get; set; }
}
 
public class MyTemplate<T1> : MyTemplate<T1, string>{}

Solution 4 - C#

C# does not support such a feature.

As you said, you can subclass it (if it's not sealed, and duplicate all constructor declarations) but it's a completely different thing.

Solution 5 - C#

Unfortunately C# does not support what you are trying to do. It would be a difficult feature to implement given that the default type for a parameter would have to adhere to the generic constraints and would most likely create headaches when the CLR tried to ensure type-safety.

Solution 6 - C#

If you want to overload the type to the interface, you can do this: Example:

public interface ISRD<TItem, TId>
{
    Task SaveAsync(TItem item);
    Task<TItem> GetAsync(TId id);
    Task DeleteAsync(TItem item);
}

public interface ISRD<TItem>: ISRD<TItem, Guid> { }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionel2iot2View Question on Stackoverflow
Solution 1 - C#Reed CopseyView Answer on Stackoverflow
Solution 2 - C#Thanasis IoannidisView Answer on Stackoverflow
Solution 3 - C#NerdroidView Answer on Stackoverflow
Solution 4 - C#mmxView Answer on Stackoverflow
Solution 5 - C#Andrew HareView Answer on Stackoverflow
Solution 6 - C#mattylantzView Answer on Stackoverflow