【发布时间】:2022-11-21 06:39:22
【问题描述】:
【问题讨论】:
-
也就是说,如果我的 T 实现了
IParseable<T>,那么我的 T 必须实现IParseable<T> -
请不要将代码粘贴为图像。始终粘贴为文本。
标签: c# recursion interface c#-11.0
【问题讨论】:
IParseable<T>,那么我的 T 必须实现IParseable<T>
标签: c# recursion interface c#-11.0
这就是所谓的Curiously_recurring_template_pattern(CRTP),据我所知,它并不是严格要求的(实际上它不能强制执行“正确”行为)但正如Preview Features in .NET 6 – Generic Math文章中提到的,它的用法是一个提示支持静态抽象接口成员调用的一个非常重要的场景——通过通用接口使用它:
这种通用模式有时称为奇怪的重复模板模式 (CRTP),是使该功能正常工作的关键。
让我们想象一下以下界面:
public interface IParseable1<TSelf> // where TSelf : IParseable1<TSelf> { static abstract TSelf Parse(string s, IFormatProvider? provider); static abstract bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out TSelf result); }和下一个方法:
static T InvariantParse<T>(string s) where T : IParseable1<T> { return T.Parse(s, CultureInfo.InvariantCulture); }如果我们实现下一个类对:
class MyClass1 { } class MyClass : IParseable1<MyClass1> { public static MyClass1 Parse(string s, IFormatProvider? provider) { throw new NotImplementedException(); } public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out MyClass1 result) { throw new NotImplementedException(); } }然后下一个调用将不会编译:
var x = InvariantParse<MyClass>("");虽然 CRTP 不会阻止“不正确”的使用(即
class MyClass1 : IParsable<MyClass1>将允许class MyClass : IParsable<MyClass1>,据我所知,没有语言结构来强制执行此类行为),但它在很大程度上暗示了所需的用法。请注意,
class MyClass : IParsable<MyClass1>可以用在类似的方法中,但它变得相当笨拙(部分原因是 C# 泛型类型推断的细节):public static TOut InvariantParseTwoGenerics<T, TOut>(string s) where T : IParseable1<TTO> { return T.Parse(s, CultureInfo.InvariantCulture); } var x1 = InvariantParseTwoGenerics<MyClass, MyClass1>("");
【讨论】:
TSelf 暗示很重。