Red de conocimiento informático - Computadora portátil - Nuevos miembros de la familia .NET: Introducción al lenguaje G#

Nuevos miembros de la familia .NET: Introducción al lenguaje G#

¿Qué es G#? G# es un nuevo lenguaje de programación que he concebido en los últimos meses. Su propósito es generar código con seguridad de tipos que se puede inyectar en tiempo de compilación o de ejecución (Inject). Code Base cuya sintaxis es un superconjunto de C# y, a diferencia de otras técnicas y herramientas de generación de código (como CodeSmith, una gran herramienta/lenguaje), G# no está pensado para usarse como punto de partida o código para consumo (Consumo), en lugar de eso lo usa G#. Tecnología de programación orientada a aspectos (AOP) para inyectar código en el código del cliente. Presentaremos rápidamente AOP porque todavía es nuevo para muchos desarrolladores. AOP o Desarrollo de software orientado a aspectos (AOSD) se creó en Xerox Parc en 1999 y es relativamente avanzado. Paradigma de software (Paradigma) La idea es simple de reducir la complejidad del desarrollo de software permitiendo a los desarrolladores centrarse en un solo dominio de problema a la vez. En otras palabras, se dice que cuando las personas intentan resolver un problema comercial (como la venta). productos en Internet), no necesitan considerar cuestiones como el inicio de sesión seguro en subprocesos, el acceso a datos y otras áreas. Esto se denomina separación de preocupaciones (Separación de preocupaciones, al separar estas áreas o aspectos, los expertos en un área específica pueden hacerlo). Desarrollar la mejor solución posible para esa área del problema, de modo que los desarrolladores ya no necesiten dominar todas las áreas de la industria. Esto puede conducir a un software robusto y completamente funcional porque el desarrollador solo necesita ser un experto en el dominio del problema del software. AOP comienza definiendo aspectos (es decir, un conjunto de comportamientos) y luego inyectando código en los métodos apropiados. Cada punto de inyección de código se denomina punto de unión. Tomemos como ejemplo la seguridad. Una forma de combatir este problema es exigir que todos los desarrolladores escriban código que verifique si hay entradas maliciosas antes de usar los datos. Es probable que los desarrolladores desarrollen un método auxiliar para resolver este problema y todos los desarrolladores simplemente llamarán a este método auxiliar. su código. AOP puede resolver este problema extrayendo estos mismos métodos auxiliares y creando un aspecto e inyectándolo en el lugar requerido. Donde se verifica la entrada del usuario, este proceso se llama tejido. En lugar de simplemente definir una lista de ubicaciones que recibirán entrada maligna. definimos un conjunto de criterios que se utilizarán en este caso. La ventaja de poder inyectar todos los métodos y constructores de propiedad pública con parámetros además de los aspectos en lugar de crear una lista es que los desarrolladores ya no tienen que depender de ellos. memoria para agregar métodos que requieren comprobaciones de entrada. En comparación con los lenguajes AOP con los que está familiarizado en la lista, como ASPectJ G#, no hay un archivo de orquestación separado. La orquestación está integrada en la sintaxis. Para la mayoría de los programadores, es indudable. Es fácil para otros inyectar código en su base de código. Sugerencias que causan pánico Para resolver este problema, G# incluye un modelo de seguridad que maneja este problema y permite al programador controlar quién puede inyectar código y qué tipo de código se puede inyectar. discutiremos más adelante en profundidad antes de echar un vistazo a algunos elementos básicos

?public class Client ?{ ?public Client() ?{ ?Messenger(Hello World ?} private void Messenger(string message); ) ?{ ?Console WriteLine( mensaje); ?} ?} géneros públicos

tor Cambiar nombre ?{ ? generación estática ChangeIt: mensaje de destino (mensaje de cadena) ?{ ?mensaje = mensaje antiguo

<; p>Aunque este ejemplo no tiene ningún propósito, demuestra una serie de características de G#. Primero, la clase Cliente usa la sintaxis estándar de C#, que es válida en G#. Simplemente envía un mensaje a la consola. Hola mundo. una nueva construcción de lenguaje en G# llamada generador. Ahora piense en el generador como un contenedor para todos los códigos que definen cómo generar código. Esto es similar a una clase. El nombre de este generador es como si Cliente fuera el nombre. de la clase A continuación, se define una generación llamada ChangeIt. Generation es similar al método y realizará algunas acciones cada vez que se llama. La diferencia es que el código generalmente se genera al llamar a la generación. ) aquí está el método Messenger de la clase Cliente. Target puede ser cualquier construcción (idioma) y también puede incluir comodines y expresiones regulares para especificar un conjunto de elementos como objetivos. Esto significa que la compilación será emitida por (Emit). en el método Messenger. Todo el código definido por la palabra clave pre entre llaves se inyectará en el código definido en el cuerpo del método Messenger. Todo el código definido entre llaves después de la palabra clave post se inyectará en el método Messenger. inyectarse después del código definido en el cuerpo del método de Messenger. Debido a que esta generación está marcada con la palabra clave estática, la inyección real del código es parte del proceso de compilación. Es importante que el programador no pueda verlo. los cambios en el método Messenger A menos que uses ilda*** o Reflector para verificar el método Messenger, otra característica que todavía es solo un sueño es poder generar una Región dinámica para que puedas abrirla en Visual para verificar qué. código que el generador ha generado en el entorno del cliente. ¿Discutiremos otros tipos de generación más adelante?

?private void Messenger(string message) ?{ ? // From ChangeIt pre block ? / Desde el bloque previo de ChangeIt ? mensaje = Hola G# ; // Desde la consola del cuerpo del método Messenger WriteLine(message); // Desde el bloque posterior de ChangIt ?Mensaje = mensaje antiguo ?}? Hola G# a la consola y luego agregue el carácter del mensaje. Cambie la cadena nuevamente al mensaje entrante original. Tenga en cuenta que las cadenas son inmutables en NET, por lo que en realidad no puede cambiar el contenido de una cadena. Por lo tanto, puede proteger el método Messenger. volver a cambiar el mensaje al mensaje original en el bloque de publicaciones. El mensaje Hola mundo no es obligatorio, pero sí para cualquier código ejecutado en el cuerpo del método Messenger.

El código inyectado es muy importante. Una pregunta lógica que surge aquí es ¿cuándo se ejecutará el código en el cuerpo del método de Messenger después de la condición de publicación? Esta pregunta lleva perfectamente a la siguiente sección

Herencia de generadores Nuestro ejemplo anterior muestra que el generador es el contenedor generado, pero también puede contener todos los miembros que la clase puede contener. (como métodos, campos, eventos, etc.) Además, la visibilidad y otros modificadores como virtual también se pueden usar para la generación. Por lo tanto, los generadores están orientados a objetos y pueden heredar entre sí. Esto permite que el generador base defina un comportamiento de inyección básico y defina comportamientos más especiales mediante subgeneradores.

? public class Client { ? public Client() ? ? Messenger(mensaje); ? } Messenger vacío privado (mensaje de cadena) ?{ ? onsole WriteLine(mensaje); ?{ ?pre ?{ ?string message = Hola G# ? } post ?{ ? ssage = message; ?} ?} } generador público Sub: Base } post? clase. La clase base usa un asterisco (*) para definir un objetivo. Puede ser reemplazado por cualquier parámetro, lo que significa que su objetivo puede ser todos los Mensajeros en la clase Cliente. Presentaremos los detalles para definir el objetivo más adelante. Por experiencia, podemos saber que una regla básica es que en la generación reescrita, se deben especificar más funciones para el objetivo. En otra parte del código, usamos la palabra clave base para acceder a la pre y publicación del generador de base. para que podamos decidir si emitir el código del generador Sub antes o después de que el generador Base emita el código

?private void Messenger(string message) ?{ ? // Base ssage = Hello G#; ? // Submensaje = mensaje ? Consola WriteLine(mensaje); // Submensaje = mensaje ?

?

La palabra clave capture se utiliza para hacer referencia a variables definidas en el mismo ámbito generado. La razón para poder acceder a estas variables incluso si la variable está definida en el generador base es que todo el código generado estará en. Lo mismo La captura de palabras clave no es necesaria al acceder a variables capturadas en el alcance, pero el método Messenger aquí usa una variable con el mismo nombre. En este caso, la captura de palabras clave es necesaria para resolver el problema de confusión. Base Es posible que la generación ChangeIt del generador defina un parámetro con el mismo nombre en su método Messenger de destino porque usamos el carácter comodín asterisco (*) en la definición. Es probable que esto suceda porque las variables locales se pueden definir durante la generación y. más adelante en él también se puede definir una variable local con el mismo nombre en una sobrecarga del método de destino. Si G# no actúa sobre él, se generará un error de compilación si se genera una variable con el mismo nombre que la variable local. se define en el método de destino. Los saltos de sección se utilizan para indicar cómo emitir código. G # proporciona la capacidad de ejecutar código en lugar de emitir código. Este símbolo se llama símbolo de sección. La fuente New Roman es como § y en la fuente Courier New (el texto original es Courier). La fuente aquí es la fuente Courier New para el mismo formato de código. Las dos son muy similares) como en § Al colocar § en el código, lo siguiente. el código se ejecutará en lugar de emitirse

  ?pre ?{ § for(int i = ; i lt; ; i ) ?§ { El código emitido por el bloque es así Console WriteLine( ) ; Consola WriteLine( ); Consola WriteLine( ); Consola WriteLine( ); cuando se emiten estas líneas de código, i se reemplaza por su valor entero. G# sabe cómo inyectar valores de tipos básicos como int y float, pero no puede emitir clases u otras personalizaciones de tipo complejo. Si § va seguido de un método, el tipo de valor de retorno del método debe ser el tipo básico void o emit. Si se trata de otros tipos, el proceso de compilación destruirá todo lo devuelto. Explicaremos la palabra clave emit. Nunca la he visto antes. un símbolo § en cualquier teclado, pero puede generar este símbolo definiendo una combinación de teclas de método abreviado. Elegí Ctrl l (L minúscula) para generar este símbolo en Word y escribí una macro para esta combinación de teclas de método abreviado en Visual para generar este símbolo <. /p>

Emisión de palabras clave Ya hemos discutido cómo emitir código usando las palabras clave pre y post, pero hay formas más completas en G# de especificar cómo y dónde emitir código. Una forma es usar palabras clave como pre y Usar la palabra clave. emitir como publicación

?emitir ?{ ?Console WriteLine(Hola G# ?}

?Code Console;

WriteLine(Hola G#); ¿Dónde se emitirá? Se emitirá en el bloque de emisión generado por su base [(Eso recuerda la definición de normal)] OK, entonces pre y post son en realidad bloques de emisión pero definen dónde se emite el código (antes del cuerpo del método y del método ( detrás del cuerpo) Para los fragmentos de código anteriores, debemos proporcionar un contexto para explicar dónde se emiten estos códigos

?pre ?{ ?§ Counter() ?} void Counter() ?{ Emit? ? { ? Console WriteLine( La palabra clave emit en acción ); ?}

Cuando se compila una compilación con este bloque previo, se llamará al método Counter debido a que hay un § símbolo en el método Counter. La palabra clave emit se utiliza para inyectar una llamada a Console WriteLine. El bloque de emisión reemplazará la llamada a Counter() con el código del bloque. No hay límite en el número de bloques de emisión en un método. y se puede colocar en el bloque de emisión Usado en § Además, emitir es solo una asignación al tipo de emisión definido en G# Framework, por lo que podemos crear una instancia de emit

?pre ?{ ?§. DisplayParts(); ?} ?public emit DisplayParts() ?{ ? emitir partOne ?{ § Inyector(partTwo); Emitir(); (emitir destino) ?{ ? Destino ?{ ? Consola WriteLine( Inyección ?} ?}

? DisplayParts y partTwo Luego usamos partOne más llaves para definir un bloque de emisión. Todo el código entre las llaves se emitirá al almacén local de partOne (Tienda local). Este local se devolverá cuando llamemos al método Emit en el objeto partOne. Almacene la última nota de que el bloque previo de este segmento de código llama a DisplayParts con un valor de retorno de tipo emt [Dado que el código emitido no se captura, se emite al bloque previo] Objetivo Ya hemos explorado cómo usar claves al apuntar a un método Las palabras pre y post, pero además G# también definen algunas palabras clave para usar otras construcciones de lenguaje como destinos. La siguiente tabla proporciona otras palabras clave que pueden emitir código y sus descripciones. También es posible especificar construcciones de destino para estas palabras clave. descripción de la palabra clave a continuación para usar comodines. ?class inyecta todas las clases en el espacio de nombres de destino. ?namespace inyecta todos los espacios de nombres en el espacio de nombres de destino.

Hay un generador. La generación inyecta todos los objetos generados definidos por el objetivo.

?generador público Base ?{ ? generación ChangeClient: cliente de destino ?{ ?property cadena pública * ?{ ?get ?{ ?post ?{ ?Console WriteLine(value) } ? Console WriteLine( Cl* Method Targeted ); ?} ?} ?}

Aquí inyectamos todos los tipos de cadenas con nombres arbitrarios. Atributos También utilizamos el valor de la palabra clave en el descriptor de acceso get. valor devuelto por el descriptor de acceso get del código de destino. El uso de pre y post aquí es el mismo que el uso en el método. El siguiente método de palabras clave define todos los métodos públicos y protegidos que inyectaremos. Los dos asteriscos (*) indican. que el tipo de valor de retorno es arbitrario y el nombre del método comienza con Cl seguido de cualquier número de caracteres. El que está entre paréntesis después del asterisco de arriba indica que el método puede tomar cualquier número de parámetros). También puede usar la libra ($. ) en el nombre como comodín para representar cualquier carácter. Es importante tener en cuenta que se cumplirán todas las restricciones de la clase Cliente.

Generación adaptativa. El segundo tipo de generación es Generación adaptativa. Simplemente reemplace la palabra clave estática delante de una generación con Generación adaptativa que se genera en tiempo de ejecución e inyecta código para que pueda verificar el estado del objeto para guiar la generación. La generación adaptativa sobre la generación estática es que terceros también pueden proporcionar marcos y componentes de generación. Los desarrolladores externos pueden crear objetivos fantasma (Phantom Target) para usarlos sin nada. La base de código conocida como objetivo fantasma no existe en la generación. framework o el framework de destino Cuando los desarrolladores desean utilizar un generador de terceros, pueden agregar el método de clase de espacio de nombres del fantasma y reubicar el código generado en su lugar apropiado en la base de código

public class Client { ? mensaje de cadena protegida; ? mensaje de cadena pública {? ) ?{ ? Consola WriteLine(mensaje); ?} ?} // Espacio de nombres de destino fantasma Seguridad de terceros ?{ ?p

Entrada del generador adaptativo público: ¿Cliente de destino {}?}

Ensamblaje lishixinzhi/Article/program/net/201311/11918