2011-03-10 16 views
15

Busco una función como¿Existe alguna forma programática para identificar palabras reservadas de C#?

public bool IsAReservedWord(string TestWord) 

Sé que podría rodar mi propia por el acaparamiento de una lista de palabras de reserva de MSDN. Sin embargo, esperaba que hubiera algo integrado en el lenguaje o en la reflexión .NET en el que se podía confiar para no tener que volver a visitar la función cuando pasase a las versiones más recientes de C# /. NET.

La razón por la que estoy buscando esto es que estoy buscando una protección en la generación de código de archivo .tt.

+3

La duda de eso. Una de las razones podría ser: hay palabras clave específicas del contexto. –

+0

... aunque si no te importa el contexto, si una cadena es una palabra clave es una prueba bastante simple. Dudo que el esfuerzo por mantener esa prueba sea algo más que trivial. Incluso MS no puede fabricar versiones de C# muy rápido. –

Respuesta

24
CSharpCodeProvider cs = new CSharpCodeProvider(); 
var test = cs.IsValidIdentifier("new"); // returns false 
var test2 = cs.IsValidIdentifier("new1"); // returns true 
+1

Tenga en cuenta que esto no lo protegerá contra la creación accidental de identificadores que comienzan con dos guiones bajos. Asegúrate de evitar hacerlo. – Brian

+0

@Brian Comprobé esto en una aplicación C# dirigida a .Net 4. La API 'IsValidIdentifier' puede devolver falso cuando hago la siguiente comprobación para una palabra clave reservada que comienza con dos caracteres de subrayado 'var test3 = cs.IsValidIdentifier (" __ arglist ") ; // devuelve falso'. Así que creo que esta API debería ser una prueba completa en ese sentido. – RBT

+0

@RBT: los prefijos de subrayado doble están reservados para uso interno y, por lo tanto, nunca deben utilizarse. Microsoft no siempre documenta palabras clave dobles de subrayado. También notaré que las palabras clave contextuales son identificadores técnicamente válidos (y por lo tanto 'IsValidIdentifier' los marca como OK), pero usarlos es mendigar problemas. Por ejemplo, probablemente no deberías usar 'yield' como nombre de variable. Probablemente existan formas de generar código ambiguo si no se bloquean las palabras clave contextuales. – Brian

3
static System.CodeDom.Compiler.CodeDomProvider CSprovider = 
      Microsoft.CSharp.CSharpCodeProvider.CreateProvider("C#"); 

    public static string QuoteName(string name) 
    { 
     return CSprovider.CreateEscapedIdentifier(name); 
    } 

    public static bool IsAReservedWord(string TestWord) 
    { 
     return QuoteName(TestWord) != TestWord; 
    } 

Dado que la definición de CreateEscapedIdentifier es:

public string CreateEscapedIdentifier(string name) 
{ 
    if (!IsKeyword(name) && !IsPrefixTwoUnderscore(name)) 
    { 
     return name; 
    } 
    return ("@" + name); 
} 

se identificará correctamente __ identificadores como reservada.

+0

Esto no funciona - 'CreateEscapedIdentifier' no escapará cadenas con dos guiones bajos principales. –

+0

@Ondrej: las cadenas con dos guiones bajos principales están reservadas, por lo que creo que es perfectamente válida. – Gabe

+0

@Gabe: depende de si desea evitarlos para evitar conflictos con la implementación o no. Desde mi punto de vista para satisfacer "buscando una protección en la generación de código de archivo .tt" 'CreateEscapedIdentifier' no es lo suficientemente fuerte. –

11

El Microsoft.CSharp.CSharpCodeGenerator tiene un método IsKeyword(string) que hace exactamente eso. Sin embargo, la clase es interna, por lo que debe usar el reflejo para acceder a ella y no hay garantía de que esté disponible en futuras versiones de .NET Framework. Tenga en cuenta que IsKeyword no se ocupa de las diferentes versiones de C#.

El método público System.CodeDom.Compiler.ICodeGenerator.IsValidIdentifier(string) rechaza las palabras clave también. El inconveniente es que este método también realiza otras validaciones, por lo que también se rechazan otras cadenas que no sean palabras clave.

Actualización: Si sólo necesita para producir un identificador válido en lugar de decidir si una cadena particular es una palabra clave, puede utilizar ICodeGenerator.CreateValidIdentifier(string). Este método se encarga de las cadenas con dos guiones bajos principales también, añadiéndoles un guión bajo más. Lo mismo vale para las palabras clave. Tenga en cuenta que ICodeGenerator.CreateEscapedIdentifier(string) prefija tales cadenas con el signo @.

Los identificadores que se inician con dos guiones bajos principales están reservados para la implementación (es decir, el compilador de C# y los generadores de códigos asociados, etc.), por lo que evitarlos es una buena idea.

Actualización 2: La razón para preferir ICodeGenerator.CreateValidIdentifier sobre ICodeGenerator.CreateEscapedIdentifier es que __x y @__x son esencialmente el mismo identificador. Lo siguiente no se compilará:

int __x = 10; 
int @__x = 20; 

En caso de que el compilador generar y utilizar un identificador __x, y el usuario utilizaría @__x como resultado de una llamada a CreateEscapedIdentifier, se produciría un error de compilación. Al usar CreateValidIdentifier, esta situación se previene porque el identificador personalizado se convierte en ___x (tres guiones bajos).

+0

hallazgo realmente genial. ¿Puede ayudarme con un ejemplo que pueda ayudarme a entender esta afirmación? El inconveniente es que este método también realiza otras validaciones, por lo que otras cadenas que no sean palabras clave también se rechazan. ¿Alguna vez se ha encontrado con una cadena que no sea de palabras clave? que fue rechazado por esta API? Será realmente interesante conocer a alguno de ellos. – RBT

7

Sin embargo yo estaba esperando que había algo integrado en el lenguaje, ya sea o .NET reflexión que se podía confiar, así que no tendría que volver a la función cuando me traslado a las nuevas versiones de C# /. RED.

Tenga en cuenta que C# nunca se ha añadido una nueva palabra clave reservada desde v1.0. Cada nueva palabra clave ha sido una palabra clave contextual sin reserva.

Aunque, por supuesto, es posible que agreguemos una nueva palabra clave reservada en el futuro, nos hemos esforzado por evitar hacerlo.

Para obtener una lista de todas las palabras clave reservadas y contextuales hasta C# 5, ver

http://ericlippert.com/2009/05/11/reserved-and-contextual-keywords/

Cuestiones relacionadas