c#固定字符串长度-编译时检查
本文关键字:编译 检查 字符串 | 更新日期: 2023-09-27 18:04:39
我想声明一个c#值类型,它只允许特定长度的字符串。所述长度应在编译时进行验证。这在Delphi中是可行的:
type
TString10 = string[10];
如果我用said字体作为
var
sTen : TString10;
sTen := '0123456789A'; //This generates a compile time error
在我看来,你不能在c#中声明一个固定长度的字符串类型。我所见过的各种解决方案都不提供c#的编译时检查。当我准备声明我自己的c#值类型结构时,这是我可以用.Format()
实现的吗?
所有的帮助和指针非常感激。
p。我真的想实现字符串长度分配的编译时检查,所以请不要"为什么你....?"
String有以下构造函数重载:
public String(char[] value)
你可以像这样创建你自己的值类型:
public struct FixedLengthString
{
private readonly string s;
public FixedLengthString(char c1, char c2, char c3)
{
this.s = new string(new [] { c1, c2, c3 });
}
}
这个特殊的例子会给你一个恰好三个字符的字符串,初始化如下:
var fls = new FixedLengthString('f', 'o', 'o');
如果你使用spec#,你可以在编译时限制各种东西,包括字符串长度。
我有一个难题给你。假设您的TString10
在c#中已经存在,并且当您分配太长的字符串时应该引发编译时错误:
string stringWithUnknownLength = "".PadLeft(new Random().Next(0, 100));
TString10 foo = stringWithUnknownLength;
应该在这里引发编译时错误吗?如果是这样,编译器如何知道何时引发它?
如您所见,编译时检查的可能性是有限的。有一些事情编译器可以很容易地验证,例如当您将特定的字符串常量分配给TString10
变量时。但是有大量的情况下,验证依赖于可能复杂的程序逻辑,或I/O,或随机数(如上面的例子)—在所有这些情况下,编译时检查是不可能的。
我本来打算给你一个围绕string
的包装器类的组合,结合代码契约的静态检查功能;然而,这种方法也会遇到同样的根本问题。总之,为了完整起见:
using System.Diagnostics.Contracts;
class TString10
{
private string value;
…
public static implicit operator TString10(string str)
{
Contract.Requires(str.Length <= 10);
return new TString10 { value = str };
}
public static implicit operator string(TString10 str10)
{
Contract.Ensures(Contract.Result<string>().Length <= 10);
return str10.value;
}
}
可以声明一个固定长度的只读char数组。只读需要避免进一步调整大小。然而,这并没有提供直接的字符串操作,但它与您希望的方式相差不大。
在我看来,没有办法单独在c#中实现这一点,因为字符串字量总是 System.String
s,并且因为c#类型系统完全忽略了数组的大小。
假设您使用自定义值类型(是的,您必须声明10个char
字段,因为char[10]
将存储在堆上),
struct String10
{
char c0;
char c1;
...
char c9;
public String10(string literal){...}
}
您可以编写一个工具(作为编译后步骤),它遍历IL并拒绝String10
构造函数的每个调用,该构造函数没有有效(即最多10个字符)字符串literal作为其参数。
new String10("0123456789") //valid
new String10("0123456789A") //rejected
new String10(someString) //has to be rejected as well → undecidable ↔ halting problem
如果你不喜欢写new String10(...)
,你可以定义一个从System.String
到String10
的隐式转换。在底层,这将是一个由c#编译器代替你调用的静态方法。
一个允许您查看IL的库是mono.cecil.
您将获得与System.String
不同的新数据类型。您可以覆盖ToString
方法,以便String10
可以在String.Format
和朋友中使用,您甚至可以定义到System.String
的扩展(隐式)转换,以便您可以将String10
与期望System.String
的api一起使用。