c# - 如何在 C# 中创建范围和同义词常量?
问题描述
我刚开始在 C# 中工作,我想将一个新类型 ( Priority
) 定义为一个整数,从 1 到 9。除此之外,我想创建三个新常量:
pri_Low, which has value 1
pri_Default, which has value 5
pri_High, which has value 9
我想做这样的事情:(C风格)
typedef TPriority = 1..9;
Const TPriority pri_Low 1;
Const TPriority pri_Default 5;
Const TPriority pri_High 9;
但是当我在互联网上寻找这个时,我得到的答案是“你需要创建一个类,你需要声明它static
,并且......”。
我的第一反应是“别着急。我只想创建一个简单的数字范围并为其中三个赋予含义。没有类,没有构造函数,没有, ,static
或public
任何花哨的东西,只是简单的基础知识。”,是这甚至是可能的,还是 C# 进入“一切都是一个类”,甚至不允许如此简单的事情?private
friend
解决方案
你需要创建一个......不,你不需要做任何事情。
但是,您可以实现一个相对简单的类型。我说是相对的,因为乍一看它看起来像很多代码,但代码本身非常简单。
是的,来自具有 1..9 类型的 Object Pascal / Delphi,我真的很想念这些类型,但遗憾的是它们在 C# 或 .NET 中不存在。
在 C# 8 中,我们得到了“范围”,但它们不是类型,它们只是值。
现在,在简单和天真的一端,您可以使用枚举:
public enum Priority
{
Low = 1,
Default = 5,
High = 9
}
但是,您现在没有 4 的优先级,如果您想让 .NET 告诉您一个值是否有效,您需要为所有有效值命名,因此您需要:
public enum Priority
{
P1 = 1, P2, P3, P4, P5, P6, P7, P8, P9,
Low = P1,
Default = P5,
High = P9
}
不幸的是,枚举不会阻止您存储无效值,这很好:
Priority p = (Priority)-5;
并且您未明确分配值的类型中的任何字段都将具有(Priority)0
默认值,而不是 5。
所以...
如果您想要一种实际上不接受小于 1 或大于 9 的值的类型,则只能自己创建一个递归,因此这里有一个简单的 Priority 类型,适用于范围 1..9:
public struct Priority : IEquatable<Priority>, IEquatable<int>,
IComparable<Priority>, IComparable<int>, IFormattable
{
private const int _lowPriority = 1;
private const int _defaultPriority = 5;
private const int _highPriority = 9;
private readonly int _value;
public Priority(int value)
{
if (value < _lowPriority || value > _highPriority)
throw new ArgumentOutOfRangeException(nameof(value),
$"value must be in the range {_lowPriority}..{_highPriority}");
_value = value - _defaultPriority;
}
// the trick with `+/- _defaultPriority` is to make sure
// new Priority() is the same as new Priority(5)
public int Value => _value + _defaultPriority;
public static Priority Parse(string s)
=> Parse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
public static Priority Parse(string s, NumberStyles style,
IFormatProvider provider)
{
if (TryParse(s, style, provider, out var priority))
return priority;
throw new FormatException($"Unable to parse priority '{s}'");
}
public static bool TryParse(string s, out Priority result)
=> TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo,
out result);
public static bool TryParse(string s, NumberStyles style,
IFormatProvider provider, out Priority result)
{
result = default;
if (s is null)
return false;
var span = s.AsSpan();
if (span.Length == 0 || span[0] != 'P')
return false;
span = span[1..];
if (!int.TryParse(span, style, provider, out int value))
return false;
if (value < _lowPriority || value > _highPriority)
return false;
result = new Priority(value);
return true;
}
public static readonly Priority Low = new Priority(_lowPriority);
public static readonly Priority Default = new Priority(_defaultPriority);
public static readonly Priority High = new Priority(_highPriority);
public static implicit operator int(Priority priority) => priority.Value;
public static explicit operator Priority(int value) => new Priority(value);
public static bool operator ==(Priority a, int b) => a.Value == b;
public static bool operator !=(Priority a, int b) => a.Value != b;
public static bool operator <(Priority a, int b) => a.Value < b;
public static bool operator >(Priority a, int b) => a.Value > b;
public static bool operator <=(Priority a, int b) => a.Value <= b;
public static bool operator >=(Priority a, int b) => a.Value >= b;
public static bool operator ==(int a, Priority b) => a == b.Value;
public static bool operator !=(int a, Priority b) => a != b.Value;
public static bool operator <(int a, Priority b) => a < b.Value;
public static bool operator >(int a, Priority b) => a > b.Value;
public static bool operator <=(int a, Priority b) => a <= b.Value;
public static bool operator >=(int a, Priority b) => a >= b.Value;
public bool Equals(Priority other) => Value == other.Value;
public bool Equals(int other) => Value == other;
public override bool Equals(object obj) => obj is Priority other
&& Equals(other);
public override int GetHashCode() => _value.GetHashCode();
public int CompareTo(Priority other) => Value.CompareTo(other.Value);
public int CompareTo(int other) => Value.CompareTo(other);
public override string ToString() => $"P{Value}";
public string ToString(string format, IFormatProvider formatProvider)
=> $"P{Value.ToString(format, formatProvider)}";
}
推荐阅读
- javascript - 为什么 swiper 进度事件不反映滑动移动?
- c++ - 如何在main函数中直接使用Locks
- c# - 如何从 Unity 中的 Parent 对象访问子脚本的方法
- sql - 显示重复列值一次,第二列不变
- r - httr GET 返回错误的内容类型
- android - Android 上的 TensorFlow Lite 对不同输入显示相同的预测
- android - 沃达丰网络阻塞 API (Chrome)?
- python - 如何更改除一个标签之外的所有文件的标签和按钮样式?
- typescript - 为什么 TypeScript 不对符号属性使用类型缩小?
- python - 发送电子邮件时,Ascii 编解码器无法编码字符