PAYATHON 2026

如何用 C# ID 字符串匹配 Mock<IOptions<T>>?

数据阿明

结论

BannedApiAnalyzers 通过符号的 Documentation Comment ID 匹配 API。IOptions<T> 的 ID 中,`1 表示泛型定义及其参数个数,并不代表可以匹配任意类型参数。因此,把它嵌入 Moq.Mock{...} 不能用来表示任意 T。

你给出的条目分别针对 Moq.Mock<IOptions<T>> 的类型和构造函数。如果其中的 IOptions 是开放泛型定义,分析器不会把该 ID 当作适用于所有 IOptions<某类型> 的模式。写上 Some.Specific.ClassName,则只会匹配这个具体的构造类型,其他类型参数不在匹配范围内。

可选做法

只禁止某个确定的类型参数

写出要禁止的类型参数的完整名称,例如:

T:Moq.Mock{Microsoft.Extensions.Options.IOptions{Some.Specific.ClassName}};Use Options.Create(...) instead of a mock.

如果要禁止构造函数,可以使用对应的成员 ID:

M:Moq.Mock{Microsoft.Extensions.Options.IOptions{Some.Specific.ClassName}}.#ctor;Use Options.Create(...) instead of a mock.

Some.Specific.ClassName 需要替换成项目中实际使用的完整类型名。这种写法只匹配这个类型参数。

禁止所有 Mock<T>

如果团队接受扩大禁用范围,可以使用你验证过有效的条目:

T:Moq.Mock`1;Use Options.Create(...) instead of a mock.

这会禁止所有 Moq.Mock<T>,范围不只包括 Mock<IOptions<T>>。T: 条目针对类型。如果还要覆盖构造函数调用,需要结合项目使用的分析器版本和诊断结果确认是否要另加构造函数条目。

需要按类型模式禁止时

如果只想禁止 Mock<IOptions<T>>,同时允许其他 Mock<T>,且 T 可以是任意类型,那么单靠这里的 C# ID 字符串无法表达这种条件。可以编写自定义 Roslyn analyzer,在语义模型中检查构造泛型类型的原始定义是否为 Moq.Mock<T>,并检查其类型参数的原始定义是否为 Microsoft.Extensions.Options.IOptions<TOptions>。这样既能覆盖不同的 TOptions,也能保留其他 Mock<T> 的用法。

具体 ID 的匹配结果可能因 Roslyn 和 BannedApiAnalyzers 版本而异。可以先在项目中用一个具体类型参数验证规则是否命中,再决定是否采用范围更广的禁用方式。

备注:内容仅供参考。