You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何IBitwiseOperators不允许泛型函数使用短路运算符?

关于泛型接口中短路运算符&&/||的编译器行为疑问

问题背景

研究向System.Boolean添加新System.Numerics接口的.NET API提案时,发现短路运算符&&和||需要实现true和false运算符,于是基于.NET 7的静态抽象运算符特性做测试验证。

测试代码定义

自定义真值运算符接口

public interface ITruthOperators<TSelf>
    where TSelf : ITruthOperators<TSelf>?
{
    static abstract bool operator true(TSelf left);

    static abstract bool operator false(TSelf left);
            
    static abstract TSelf operator !(TSelf left);

    static abstract TSelf TruthyIdentity { get; }
            
    static abstract TSelf FalseyIdentity { get; }
}

自定义布尔类型

实现上述接口与IBitwiseOperators<MyBool, MyBool, MyBool>:

public struct MyBool(bool val) : ITruthOperators<MyBool>, IBitwiseOperators<MyBool, MyBool, MyBool>
{
    public bool Value {get;} = val;
    
    public static bool operator true(MyBool b) => b.Value;
    
    public static bool operator false(MyBool b) => !b.Value;
    
    public static MyBool operator !(MyBool b) => new(!b.Value);

    public static MyBool TruthyIdentity => new(true);
    
    public static MyBool FalseyIdentity => new(false);
    
    public static MyBool operator &(MyBool a, MyBool b) => new(a.Value & b.Value);
    
    public static MyBool operator |(MyBool a, MyBool b) => new(a.Value | b.Value);
    
    public static MyBool operator ^(MyBool a, MyBool b) => new(a.Value ^ b.Value);
    
    public static MyBool operator ~(MyBool val) => new(!val.Value);
}

问题现象

此时可以正常编写if (T.TruthyIdentity)、if (!someMyBool)这类代码,也能使用非短路运算符someMyBool & someOtherMyBool,但短路运算符无法使用。

编写如下泛型函数:

public T IsTrue<T>(T a, T b) where T : ITruthOperators<T>, IBitwiseOperators<T, T, T>
{
    return a && b;
}

会触发错误:

要作为短路运算符适用,用户定义的逻辑运算符('IBitwiseOperators<T, T, T>.operator &(T, T)')必须具有相同的返回类型和参数类型

但实际上,当IBitwiseOperators<TSelf, TOther, TResult>实例化为IBitwiseOperators<MyBool, MyBool, MyBool>时,operator &的参数和返回类型均为MyBool,完全符合要求。

排查尝试

重新定义仅包含同类型参数与返回值的自定义位运算符接口:

public interface IBitwiseOperators<TSelf>
    where TSelf : IBitwiseOperators<TSelf>?
{
    static abstract TSelf operator &(TSelf left, TSelf right);

    static abstract TSelf operator |(TSelf left, TSelf right);

    static abstract TSelf operator ^(TSelf left, TSelf right);

    static abstract TSelf operator ~(TSelf value);
}

将泛型函数约束改为where T : ITruthOperators<T>, IBitwiseOperators<T>后,又出现新错误:

要使'IBitwiseOperators.operator &(T, T)'可用作短路运算符,其声明类型'IBitwiseOperators'必须定义true和false运算符

明明T同时约束了两个接口,ITruthOperators<T>已定义true/false运算符,该错误不符合预期。

目前唯一可行的方式是将true/false运算符与位运算符放在同一个接口中。

C#规范参考

根据C#规范中关于短路运算符的定义:

当&&或||的操作数属于声明了适用用户定义运算符&或|的类型时,以下两个条件必须同时成立,其中T是所选运算符的声明类型:

  • 所选运算符的返回类型和每个参数的类型都必须是T。即运算符应计算两个T类型操作数的逻辑AND或OR,并返回T类型的结果。
  • T必须包含true和false运算符的声明。
    如果任一要求未满足,则会发生绑定时代错误。否则,&&或||操作通过将用户定义的true或false运算符与所选用户定义运算符结合来计算。

这里的疑问是:“所选运算符的声明类型”指的是接口还是泛型类型?按逻辑应该是泛型类型T,因为我们处理的是约束到这些接口的泛型类型,变量实际类型为T。

核心问题

这种编译器行为是设计如此,还是属于bug?


内容的提问来源于stack exchange,提问作者Charlieface

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 18:35:17