对于 C # 泛型中的“默认”类型参数是否有合理的解决方案?

在 C + + 模板中,可以指定某个类型参数为默认值。即,除非明确指定,否则它将使用 T 类型。

这可以在 C # 中实现或近似吗?

我要找的是这样的东西:

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

因此,一个没有显式指定 T2的类型的实例:

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

基本上是:

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

最后,我在寻找一个案例,其中有一个相当广泛使用的模板,但我正在考虑扩展与一个额外的类型参数。我想我可以继承类,但我很好奇在这种情况下是否还有其他选择。

36037 次浏览

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.

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.

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.

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

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>{}

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> { }