C#11环境下代码莫名触发CS0315错误,求排查原因
AllFlagsViaBitwise报CS0315错误的原因及解决 问题描述
我在VS2022中基于.NET7(C#11)创建新项目,编写代码调用AllFlagsViaBitwise方法时触发以下错误:
Error 1 CS0315 类型“ConsoleAppTestEnumAll.Program.Options”不能用作泛型类型或方法“IBitwiseOperators<TSelf, TOther, TResult>”中的类型参数“TSelf”。不存在从“ConsoleAppTestEnumAll.Program.Options”到“System.Numerics.IBitwiseOperators<ConsoleAppTestEnumAll.Program.Options, int, ConsoleAppTestEnumAll.Program.Options>”的装箱转换。 ConsoleAppTestEnumAll C:\prj\Personnel\ConsoleAppTestEnumAll\ConsoleAppTestEnumAll\Program.cs 10 Active
根据StackOverflow用户Petrusion的测试,这段代码应当可以正常编译运行,但我本地却出现上述错误,请问原因是什么?
注:我认为这属于C#11(.NET7)的新特性范畴。
代码示例
using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; namespace ConsoleAppTestEnumAll { internal class Program { [Flags] public enum Options { Opt1 = 1, Opt2 = 2, Opt4= 4, } public class EnumUtil { public static T AllFlagsViaBitwise<T>() where T : unmanaged, Enum, IBitwiseOperators<T, T, T>, IEqualityOperators<T, T, bool> { T result = default; foreach (var value in Enum.GetValues<T>()) { if ((result & value) != default) { throw new ArgumentException( $"{typeof(T).Name} is not a flags enum. Detected at enum value {value}", nameof(T)); } result |= value; } return result; } } static void Main(string[] args) { Debug.Assert(EnumUtil.AllFlagsViaBitwise<Options>() == 7); } } }
项目配置
- 目标框架:.NET 7
- C#语言版本:11.0
错误原因
在.NET7中,枚举类型不会自动实现IBitwiseOperators<T, T, T>等静态抽象运算符接口,这是.NET8才新增的特性(.NET8中枚举默认实现了IBitwiseOperators、IEqualityOperators等接口)。Petrusion的测试能通过,大概率是他使用了.NET8而非.NET7环境。
解决方法
你有两种选择来修复这个错误:
升级项目到.NET8
修改项目目标框架为.NET8(需确保VS2022版本在17.7及以上),此时枚举会默认实现所需的运算符接口,代码无需修改即可编译运行。手动为枚举实现运算符接口
在.NET7环境下,显式为Options枚举添加IBitwiseOperators和IEqualityOperators的实现:[Flags] public enum Options : int, IBitwiseOperators<Options, Options, Options>, IEqualityOperators<Options, Options, bool> { Opt1 = 1, Opt2 = 2, Opt4 = 4, } // 实现所需的静态运算符 public static Options operator &(Options left, Options right) => (Options)((int)left & (int)right); public static Options operator |(Options left, Options right) => (Options)((int)left | (int)right); public static Options operator ^(Options left, Options right) => (Options)((int)left ^ (int)right); public static Options operator ~(Options value) => (Options)~(int)value; public static bool operator ==(Options left, Options right) => left.Equals(right); public static bool operator !=(Options left, Options right) => !left.Equals(right);
内容的提问来源于stack exchange,提问作者Eric Ouellet

