检查字符串是否是编译时已知的文字字符串?

时间:2015-06-24 20:03:26

标签: c# string

我正在写一个库,我有一个接受字典的方法。字典的值是不受信任/不安全的,但密钥是可信的,如果最终用户能够输入任意密钥名称,则可能发生“坏事”。

因此,当其他开发人员使用此库函数时,我想强制他们在编译时知道密钥名称。所以这样的事情是允许的:

string userInput = Console.ReadLine(); 
Dictionary<string, string> something = new Dictionary<string, string>();   
something.Add("MyKey", userInput);    

因为“MyKey”是一个字符串文字,在编译时已知。但是这样的事情会引发编译或运行时异常:

string userInput = Console.ReadLine();
string userKey = Console.ReadLine(); 
Dictionary<string, string> something = new Dictionary<string, string>();   
something.Add(userKey, userInput);    

因为用户输入用于密钥(userKey),因此在编译时它是未知的。

我查看过GetType(),并没有什么能真正区分文字字符串和运行时创建的字符串。

3 个答案:

答案 0 :(得分:3)

您可以使用string.IsInterned来确定字符串是否被实习。默认情况下,所有编译时文字都将被实现,但您可以使用编译器标志将其关闭。

这是运行时检查,而不是编译时检查。

另请注意,可以使用string.Intern函数实现非编译时间文字,因此技术上您可以让非文字字符串通过您的测试。但是如果你的程序要么在任何时候都没有实习字符串,要么只有你知道的实际字符串是安全的,那么这可能会有效。

另一个选项,如果你的所有密钥都应该在编译时知道,那就是没有密钥就是字符串。例如,将密钥设为枚举,以便您知道可以用作密钥的唯一值位于您在编译时修复的列表中。

答案 1 :(得分:2)

未经过广泛测试,但通过使用表达式而不是直接值,您可以测试传递的值的类型。 e.g。

void Add(Expression<Func<string>> fn)
{
        if (fn.Body.NodeType != ExpressionType.Constant)
            throw new ArgumentException("Only literal strings are allowed");

        //and extra check if the value itself is interned
        var val = fn.Compile()();
        if (string.IsInterned(val) == null)
            throw new ArgumentException("Only literal strings are allowed");

}

然后开发人员必须将参数作为lambda传递:

  Add(() => "Test"); //Valid
  string somestring = "Test";
  Add(() => somestring); //Error

答案 2 :(得分:2)

我可以想到两种可能的方式,都使用反射:

值得一提的是,两者都可能被客户端代码伪造。例如,可以使用dynamic assembliesSystem.ComponentModel.TypeDescriptor类。