我想声明一个只允许特定长度的字符串的C#值类型。所述长度应在编译时验证。这在Delphi中是可行的:
type
TString10 = string[10];
如果我使用所说的tyoe:
var
sTen : TString10;
sTen := '0123456789A'; //This generates a compile time error
据我所知,你不能在C#中声明一个固定长度的字符串类型。我见过的各种解决方案都不提供编译时间检查C#。因为我准备声明我自己的C#值类型结构,这是我能用.Format()
实现的吗?
所有帮助和指示非常感谢。
PS。我真的希望实现字符串长度分配的编译时检查,所以请不要“你为什么......?”
答案 0 :(得分:5)
鉴于System.String具有this constructor overload:
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');
答案 1 :(得分:3)
如果使用Spec#,则可以在编译时限制各种内容,包括字符串长度。
答案 2 :(得分:3)
我有一个难题。假设您的TString10
已经存在于C#中,并且在分配太长的字符串时应该引发编译时错误:
string stringWithUnknownLength = "".PadLeft(new Random().Next(0, 100));
TString10 foo = stringWithUnknownLength;
这里是否应该引发编译时错误?如果是这样,编译器如何知道 何时提升它?
如您所见,编译时检查的可能性有限。编译器可以轻松验证某些内容,例如将特定字符串常量分配给TString10
变量时。但是有大量的情况,验证取决于可能复杂的程序逻辑,或I / O,或随机数(如上例所示) - 在所有这些情况下,编译时间检查是不可能的。
我原本打算向你推荐一个围绕string
的包装类的组合,结合Code Contracts的静态检查功能;但是,这种方法会遇到同样的根本问题。无论如何,为了完整起见:
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;
}
}
答案 3 :(得分:1)
您可以声明一个固定长度的readonly char数组。只需要避免进一步调整大小。但是,这不是直接的字符串操作,但它与你想要的方式并不太远。
答案 4 :(得分:1)
我看到它的方式,单凭C#无法实现这一点,因为字符串文字是总是 System.String
并且因为C#类型系统完全无视数组尺寸。
假设您使用自定义值类型(是的,您必须声明10个char
字段,因为char[10]
将存储在堆上),
struct String10
{
char c0;
char c1;
...
char c9;
public String10(string literal){...}
}
您可以编写一个工具(作为编译后步骤),通过IL并拒绝每个没有有效(即最多10个字符)字符串的String10
构造函数的调用 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。