Literal de cadena sin formato
Nota
Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos e se incorporan en la especificación ECMA actual.
Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.
Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C# en el artículo sobre las especificaciones de .
Resumen
Permite una nueva forma de literal de cadena que comienza con un mínimo de tres caracteres de """
(pero no como máximo), seguido opcionalmente de una new_line
, el contenido de la cadena y, a continuación, termina con el mismo número de comillas con las que se inició el literal. Por ejemplo:
var xml = """
<element attr="content"/>
""";
Dado que el contenido anidado podría querer usar """
, los delimitadores iniciales o finales pueden ser más largos como el siguiente:
var xml = """"
Ok to use """ here
"""";
Para que el texto sea fácil de leer y permita la sangría que les gusta a los desarrolladores en el código, estos literales de cadena quitarán de forma natural la sangría especificada en la última línea al generar el valor literal final. Por ejemplo, un literal con el formato:
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Incluirá el contenido:
<element attr="content">
<body>
</body>
</element>
Esto permite que el código tenga un aspecto natural, a la vez que genera literales deseados y evita los costos en tiempo de ejecución si esto requiere el uso de rutinas especializadas de manipulación de cadenas.
Si no se desea el comportamiento de sangría, también es trivial deshabilitarlo de la siguiente manera:
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
También se admite un formulario de una sola línea. Comienza con un mínimo de tres caracteres """
(pero no máximo), el contenido de la cadena (que no puede contener ningún carácter new_line
) y, a continuación, termina con el mismo número de comillas con las que comenzó el literal. Por ejemplo:
var xml = """<summary><element attr="content"/></summary>""";
También se admiten cadenas de texto literales no procesadas interpoladas. En este caso, la cadena especifica el número de llaves necesarias para iniciar una interpolación (determinada por el número de signos de dólar presentes al principio del literal). Cualquier secuencia de llaves que tenga menos llaves que esa simplemente se trata como contenido. Por ejemplo:
var json = $$"""
{
"summary": "text",
"length" : {{value.Length}},
};
""";
Motivación
C# carece de una manera general de crear literales de cadena simples que puedan contener eficazmente cualquier texto arbitrario. En la actualidad, todos los formularios literales de cadena de C# necesitan alguna forma de escape en caso de que el contenido use algún carácter especial (siempre si se usa un delimitador). Esto evita tener fácilmente literales que contengan otros lenguajes (por ejemplo, un literal XML, HTML o JSON).
Todos los enfoques actuales para formar estos literales en C# hoy siempre obligan al usuario a escapar manualmente del contenido. La edición en ese punto puede ser muy molesta, ya que el escape no se puede evitar y debe tratarse siempre que surja en los contenidos. Esto es especialmente molesto para las expresiones regulares, especialmente cuando contienen comillas o barras diagonales inversas. Incluso con una cadena textual (@""
), las comillas se deben escapar, lo que conduce a una combinación de C# y expresión regular intercalada. {
y }
son igualmente frustrantes en cadenas interpoladas ($""
).
El argumento del problema es que todas nuestras cadenas tienen un delimitador de inicio/fin fijo. Siempre que sea así, siempre tendremos que tener un mecanismo de escape, ya que es posible que el contenido de la cadena tenga que especificar ese delimitador final en su contenido. Esto es especialmente problemático, ya que el delimitador "
es muy común en muchos lenguajes.
Para abordar esto, esta propuesta permite delimitadores de inicio y finalización flexibles para que siempre se puedan realizar de forma que no entren en conflicto con el contenido de la cadena.
Metas
- Proporcione un mecanismo que permita que el usuario proporcione todos los valores de cadena sin necesidad de ningún tipo de secuencia de escape. Dado que todas las cadenas deben ser representables sin secuencias de escape, siempre debe ser posible que el usuario especifique delimitadores que se garantizará que no entren en conflicto con ningún contenido de texto.
- Admite interpolaciones de la misma manera. Como se indicó anteriormente, dado que todas las cadenas deben ser representables sin escapes, siempre debe ser posible que el usuario especifique un delimitador de
interpolation
que se garantizará que no entre en conflicto con ningún contenido de texto. Es importante que los lenguajes que usan nuestros caracteres delimitadores de interpolación ({
y}
) sean de primera clase y no resulten difíciles de usar. - Los literales de cadena multilínea deben tener un aspecto agradable en el código y no deben hacer que la sangría dentro de la unidad de compilación tenga un aspecto extraño. Es importante que los valores literales que no están indentados no se deben forzar a ocupar la primera columna del archivo, ya que pueden interrumpir el flujo del código y parecerán desalineados con el resto del código circundante.
- Este comportamiento debería ser fácil de anular manteniendo los literales claros y fáciles de leer.
- Para todas las cadenas que no contengan por sí mismas una
new_line
o que no comiencen o terminen con un carácter de comillas ("
), debe ser posible representar el literal de cadena en una sola línea.- Opcionalmente, con complejidad adicional, podríamos ajustar esto para indicar que: para todas las cadenas que no contienen una
new_line
(pero que pueden comenzar o terminar con el carácter de comilla"
), debería ser posible representar el literal de la cadena en sí mismo en una sola línea. Para obtener más información, consulte la propuesta ampliada en la secciónDrawbacks
.
- Opcionalmente, con complejidad adicional, podríamos ajustar esto para indicar que: para todas las cadenas que no contienen una
Diseño detallado (caso de no interpolación)
Agregaremos una nueva producción de string_literal
con el siguiente formato:
string_literal
: regular_string_literal
| verbatim_string_literal
| raw_string_literal
;
raw_string_literal
: single_line_raw_string_literal
| multi_line_raw_string_literal
;
raw_string_literal_delimiter
: """
| """"
| """""
| etc.
;
raw_content
: not_new_line+
;
single_line_raw_string_literal
: raw_string_literal_delimiter raw_content raw_string_literal_delimiter
;
multi_line_raw_string_literal
: raw_string_literal_delimiter whitespace* new_line (raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
;
not_new_line
: <any unicode character that is not new_line>
;
El delimitador final de un raw_string_literal
debe coincidir con el delimitador inicial. Por lo tanto, si el delimitador inicial es """""
el delimitador final debe ser así.
La gramática anterior para una raw_string_literal
debe interpretarse como:
- Comienza con al menos tres comillas (pero sin límite superior entre comillas).
- A continuación, continúa con el contenido en la misma línea que las comillas iniciales. Este contenido en la misma línea puede estar en blanco o no en blanco. 'blank' es sinónimo de 'espacio en blanco'.
- Si el contenido de esa misma línea no está en blanco, no puede seguir ningún contenido adicional. En otras palabras, el literal debe terminar con el mismo número de comillas en esa misma línea.
- Si el contenido de la misma línea está en blanco, el literal puede continuar con una
new_line
y algún número de líneas de contenido posteriores ynew_line
s.- Una línea de contenido es cualquier texto excepto un
new_line
. - A continuación, termina con una
new_line
seguida de un número (posiblemente cero) dewhitespace
y el mismo número de comillas con las que se inició el literal.
- Una línea de contenido es cualquier texto excepto un
Valor de literal de cadena sin formato
Las partes entre el raw_string_literal_delimiter
inicial y final se usan para formar el valor del raw_string_literal
de la siguiente manera:
- En el caso de
single_line_raw_string_literal
, el valor del literal será exactamente el contenido entre elraw_string_literal_delimiter
inicial y final. - En el caso de
multi_line_raw_string_literal
elwhitespace* new_line
inicial y elnew_line whitespace*
final no forma parte del valor de la cadena. Sin embargo, la parte final dewhitespace*
precedente al terminalraw_string_literal_delimiter
se considera el "espacio en blanco de sangría" y afectará a cómo se interpretan las otras líneas. - Para obtener el valor final, se recorre la secuencia de
(raw_content | new_line)*
y se realiza lo siguiente:- Si es un
new_line
el contenido delnew_line
se agrega al valor de cadena final. - Si no es un
raw_content
"en blanco" (es decir,not_new_line+
contiene un carácter nowhitespace
):- el "espacio en blanco de sangría" debe ser un prefijo del
raw_content
. De lo contrario, es un error. - el "espacio en blanco de sangría" se elimina del inicio de
raw_content
y el resto se agrega al valor final de la cadena.
- el "espacio en blanco de sangría" debe ser un prefijo del
- Si es un
raw_content
"en blanco" (es decir,not_new_line+
es completamentewhitespace
):- El "espacio en blanco de sangría" debe ser un prefijo de
raw_content
oraw_content
debe ser un prefijo del "espacio en blanco de sangría". De lo contrario, es un error. - la mayor parte del "espacio en blanco de sangría" se quita del principio de
raw_content
y cualquier resto se agrega al valor de cadena final.
- El "espacio en blanco de sangría" debe ser un prefijo de
- Si es un
Aclaraciones:
Un
single_line_raw_string_literal
no es capaz de representar una cadena con un valornew_line
en él. Unsingle_line_raw_string_literal
no participa en el recorte de "espacios en blanco de sangría". Su valor son siempre los caracteres exactos entre los delimitadores inicial y final.Dado que un
multi_line_raw_string_literal
omite elnew_line
final de la última línea de contenido, lo siguiente representa una cadena sinnew_line
inicial y sin terminaciónnew_line
var v1 = """
This is the entire content of the string.
""";
Esto mantiene la simetría con la forma en que se omite la new_line
inicial y también proporciona una manera uniforme de asegurarse de que siempre se pueda ajustar el "espacio en blanco de sangría". Para representar una cadena con un terminal new_line
se debe proporcionar una línea adicional de la siguiente manera:
var v1 = """
This string ends with a new line.
""";
Un
single_line_raw_string_literal
no puede representar un valor de cadena que comience o termine con una comilla ("
), aunque se proporciona una ampliación a esta propuesta en la secciónDrawbacks
que muestra cómo pueda admitirse.Un
multi_line_raw_string_literal
comienza conwhitespace* new_line
después delraw_string_literal_delimiter
inicial. Este contenido después del delimitador se omite por completo y no se usa de ninguna manera al determinar el valor de la cadena. Esto permite que un mecanismo especifique unraw_string_literal
cuyo contenido comienza con un carácter"
. Por ejemplo:
var v1 = """
"The content of this string starts with a quote
""";
- Un
raw_string_literal
también puede representar el contenido que termina con una comilla ("
). Esto se admite porque el delimitador de terminación debe estar en su propia línea. Por ejemplo:
var v1 = """
"The content of this string starts and ends with a quote"
""";
var v1 = """
""The content of this string starts and ends with two quotes""
""";
- El requisito de que un
raw_content
'en blanco' sea un prefijo del 'espacio en blanco de sangría' o de que el 'espacio en blanco de sangría' sea un prefijo de este, ayuda a asegurar que no se produzcan escenarios confusos con espacios en blanco mixtos, especialmente porque quedaría poco claro qué debería suceder con esa línea. Por ejemplo, el siguiente caso es ilegal:
var v1 = """
Start
<tab>
End
""";
Aquí el "espacio en blanco de sangría" consiste en nueve caracteres de espacio, pero el
raw_content
"en blanco" no comienza con dicho prefijo. No hay una respuesta clara en absoluto sobre cómo se debe tratar la línea<tab>
. ¿Debe omitirse? ¿Debería ser igual que.........<tab>
? Por lo tanto, hacer que sea ilegal parece el más claro para evitar confusiones.Sin embargo, los casos siguientes son legales y representan la misma cadena:
var v1 = """
Start
<four spaces>
End
""";
var v1 = """
Start
<nine spaces>
End
""";
En ambos casos, el "espacio en blanco de sangría" será de nueve espacios. Y en ambos casos, quitaremos tanto de ese prefijo como sea posible, de modo que el raw_content
quede en blanco en cada caso, sin tener en cuenta cada new_line
. Esto permite a los usuarios no tener que ver y potencialmente preocuparse por el espacio en blanco en estas líneas cuando copian o pegan o editan estas líneas.
- Sin embargo, en el caso de:
var v1 = """
Start
<ten spaces>
End
""";
El "espacio en blanco de sangría" seguirá siendo de nueve espacios. Sin embargo, quitaremos la mayor cantidad posible de los "espacios en blanco de sangría" y el raw_content
"en blanco" aportará un único espacio en el contenido final. Esto permite casos en los que el contenido necesita espacios en blanco en estas líneas que se deben conservar.
- Técnicamente, lo siguiente no es legal:
var v1 = """
""";
Esto se debe a que el inicio de la cadena sin formato debe tener una new_line
(que la tiene) pero el final debe tener también una new_line
(que no la tiene). El raw_string_literal
mínimo legal es:
var v1 = """
""";
Sin embargo, esta cadena es decididamente poco interesante, ya que es equivalente a ""
.
Ejemplos de sangría
El algoritmo de "espacio en blanco de sangría" se puede visualizar en varias entradas de la siguiente manera. En los ejemplos siguientes se usa el carácter de barra vertical |
para ilustrar la primera columna de la cadena sin formato resultante:
Ejemplo 1: caso estándar
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
se interpreta como
var xml = """
|<element attr="content">
| <body>
| </body>
|</element>
""";
Ejemplo 2: delimitador final en la misma línea que el contenido.
var xml = """
<element attr="content">
<body>
</body>
</element>""";
Esto es ilegal. La última línea de contenido debe terminar con un new_line
.
Ejemplo 3: Delimitador final antes del delimitador inicial
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
se interpreta como
var xml = """
| <element attr="content">
| <body>
| </body>
| </element>
""";
Ejemplo 4: Delimitador final después del delimitador inicial
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Esto es ilegal. Las líneas de contenido deben comenzar con "el espacio en blanco de sangría".
Ejemplo 5: Línea vacía en blanco
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
se interpreta como
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
Ejemplo 6: Línea en blanco con menos espacios en blanco que el prefijo (los puntos representan espacios)
var xml = """
<element attr="content">
<body>
</body>
....
</element>
""";
se interpreta como
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
Ejemplo 7: Línea en blanco con más espacios en blanco que el prefijo (los puntos representan espacios)
var xml = """
<element attr="content">
<body>
</body>
..............
</element>
""";
se interpreta como
var xml = """
|<element attr="content">
| <body>
| </body>
|....
|</element>
""";
Diseño detallado (caso de interpolación)
Las interpolaciones en cadenas interpoladas normales (por ejemplo, $"..."
) se admiten hoy en día mediante el uso del carácter de {
para iniciar una interpolation
y el uso de una secuencia de escape {{
para insertar un carácter de llave de apertura real. El uso de este mismo mecanismo infringiría los objetivos '1' y '2' de esta propuesta. Los lenguajes que tienen {
como carácter principal (por ejemplo, JavaScript, JSON, Regex e incluso C# incrustado) ahora necesitarían escaparse, anulando el propósito de los literales de cadena sin formato.
Para admitir interpolaciones, las presentamos de una manera diferente a las cadenas interpoladas normales $"
. En concreto, un interpolated_raw_string_literal
comenzará con algunos caracteres de tipo $
. El recuento de estos indica cuántos caracteres {
(y }
) son necesarios en el contenido del literal para delimitar el interpolation
. Es importante indicar que sigue sin haber ningún mecanismo de escape para llaves. En su lugar, al igual que con las comillas ("
), el propio literal siempre puede asegurarse de que especifica delimitadores para las interpolaciones que están seguras de no colisionar con ninguno del resto del contenido de la cadena. Por ejemplo, un literal JSON que contiene agujeros de interpolación se puede escribir de la siguiente manera:
var v1 = $$"""
{
"orders":
[
{ "number": {{order_number}} }
]
}
"""
Aquí, {{...}}
coincide con la cantidad requerida de dos llaves especificadas por el delimitador con prefijo $$
. En el caso de una sola $
que significa que la interpolación se especifica como {...}
, como en los literales de cadenas interpolados normales. Es importante indicar que esto significa que un literal interpolado con caracteres N
$
puede tener una secuencia de llaves 2*N-1
(del mismo tipo en una fila). Las últimas llaves N
iniciarán (o finalizarán) una interpolación y las llaves N-1
restantes solo serán contenido. Por ejemplo:
var v1 = $$"""X{{{1+1}}}Z""";
En este caso, las dos llaves internas {{
y }}
pertenecen a la interpolación, y las llaves singulares externas son solo contenido. Por lo tanto, la cadena anterior es equivalente al contenido X{2}Z
. Tener 2*N
(o más) llaves siempre es un error. Para tener secuencias más largas de llaves como contenido, la cantidad de caracteres $
debe aumentarse en consecuencia.
Los literales de cadena sin procesar interpolados se definen como:
interpolated_raw_string_literal
: single_line_interpolated_raw_string_literal
| multi_line_interpolated_raw_string_literal
;
interpolated_raw_string_start
: $
| $$
| $$$
| etc.
;
interpolated_raw_string_literal_delimiter
: interpolated_raw_string_start raw_string_literal_delimiter
;
single_line_interpolated_raw_string_literal
: interpolated_raw_string_literal_delimiter interpolated_raw_content raw_string_literal_delimiter
;
multi_line_interpolated_raw_string_literal
: interpolated_raw_string_literal_delimiter whitespace* new_line (interpolated_raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
;
interpolated_raw_content
: (not_new_line | raw_interpolation)+
;
raw_interpolation
: raw_interpolation_start interpolation raw_interpolation_end
;
raw_interpolation_start
: {
| {{
| {{{
| etc.
;
raw_interpolation_end
: }
| }}
| }}}
| etc.
;
Lo anterior es similar a la definición de raw_string_literal
, pero con algunas diferencias importantes. Un interpolated_raw_string_literal
debe interpretarse como:
- Comienza con al menos un signo de dólar (pero sin límite superior) y luego tres comillas (también sin límite superior).
- A continuación, continúa con el contenido en la misma línea que las comillas iniciales. Este contenido de la misma línea puede estar en blanco o no en blanco. 'blank' es sinónimo de 'espacio en blanco'.
- Si el contenido de esa misma línea no está en blanco, no puede seguir contenido adicional. En otras palabras, el literal debe terminar con el mismo número de comillas en esa misma línea.
- Si el contenido de la misma línea está en blanco, el literal puede continuar con una
new_line
y algún número de líneas de contenido posteriores ynew_line
s.- Una línea de contenido es cualquier texto excepto un
new_line
. - Una línea de contenido puede contener múltiples ocurrencias de
raw_interpolation
en cualquier posición. Laraw_interpolation
debe comenzar con un número igual de llaves de apertura ({
) como el número de signos de dólar al principio del literal. - Si el 'espacio en blanco de sangría' no está vacío, una
raw_interpolation
no puede seguir inmediatamente a unanew_line
. - El
raw_interpolation
seguirá las reglas normales especificadas en §12.8.3. Cualquierraw_interpolation
debe terminar con el mismo número de llaves de cierre (}
) que los signos de dólar y las llaves de apertura. - Cualquier
interpolation
puede contener líneas nuevas dentro de la misma manera que uninterpolation
en unverbatim_string_literal
normal (@""
). - A continuación, termina con una
new_line
seguida de un número (posiblemente cero) dewhitespace
y el mismo número de comillas con las que se inició el literal.
- Una línea de contenido es cualquier texto excepto un
El cálculo del valor de cadena interpolada sigue las mismas reglas que un raw_string_literal
normal, excepto que se actualiza para controlar las líneas que contienen raw_interpolation
s. La creación del valor de cadena se produce de la misma manera, solo con los agujeros de interpolación reemplazados por los valores que producen esas expresiones en tiempo de ejecución. Si el interpolated_raw_string_literal
se convierte en un FormattableString
, los valores de las interpolaciones se pasan en su orden respectivo a la matriz de arguments
a FormattableString.Create
. El resto del contenido del interpolated_raw_string_literal
después de que el "espacio en blanco de sangría" se haya quitado de todas las líneas se usará para generar la cadena format
pasada a FormattableString.Create
, excepto con el contenido {N}
numerado adecuadamente en cada ubicación donde se produjo una raw_interpolation
(o {N,constant}
en caso de que su interpolation
tenga el formato expression ',' constant_expression
).
Hay una ambigüedad en la especificación anterior. En concreto, cuando una sección de {
en el texto y {
de una interpolación se juntan. Por ejemplo:
var v1 = $$"""
{{{order_number}}}
"""
Esto puede interpretarse como: {{ {order_number } }}
o { {{order_number}} }
. Sin embargo, como el anterior no es válido (ninguna expresión de C# podría empezar con {
) sería inútil interpretar de esa manera. Por lo tanto, interpretamos de esta última manera, donde las llaves {
y }
más internas forman la interpolación, y las llaves más externas forman el texto. En el futuro, esto podría ser un problema si el lenguaje de programación admite alguna vez expresiones que están rodeadas por llaves. Sin embargo, en ese caso, la recomendación sería escribir tal caso como el siguiente: {{({some_new_expression_form})}}
. Aquí, los paréntesis ayudarán a distinguir la parte de expresión del resto del literal/interpolación. Esto ya tiene prioridad con la forma en que las expresiones condicionales ternarias deben encapsularse para no entrar en conflicto con el especificador de formato o alineación de una interpolación (por ejemplo, {(x ? y : z)}
).
Inconvenientes
Los literales de cadenas sin formato añaden más complejidad al lenguaje. Ya tenemos muchas formas literales de cadenas de texto para numerosos propósitos. Las cadenas ""
, @""
y $""
ya tienen mucha potencia y flexibilidad. Pero todas carecen de una manera de proporcionar contenido sin procesar que nunca se necesiten escapar.
Las reglas anteriores no admiten el caso de 4.a:
- ...
- Opcionalmente, con complejidad adicional, podríamos ajustar esto para indicar que: para todas las cadenas que no contienen una
new_line
(pero que pueden comenzar o terminar con el carácter de comilla"
), debería ser posible representar el literal de la cadena en sí mismo en una sola línea.
- Opcionalmente, con complejidad adicional, podríamos ajustar esto para indicar que: para todas las cadenas que no contienen una
Esto se debe a que no tenemos medios para saber que una comilla inicial o final ("
) debe pertenecer al contenido y no al propio delimitador. Sin embargo, si se trata de un escenario importante que queremos admitir, podemos agregar una construcción de '''
paralela para continuar con el formato """
. Con esa construcción paralela, se puede escribir fácilmente una cadena de una sola línea que comienza y termina con "
como '''"This string starts and ends with quotes"'''
junto con la construcción paralela """'This string starts and ends with apostrophes'"""
. Esto también podría ser útil para separar visualmente los caracteres de comillas, lo cual es beneficioso al insertar idiomas que utilizan predominantemente un tipo de comilla más que otro.
Alternativas
https://github.com/dotnet/csharplang/discussions/89 cubre muchas opciones aquí. Las alternativas son numerosas, pero creo que se desvían demasiado hacia la complejidad y la mala ergonomía. Este enfoque opta por la simplicidad donde simplemente aumentas la longitud de la comilla inicial/final hasta que no haya preocupación por un conflicto con el contenido de la cadena. También permite que el código que escriba tenga una buena sangría, al tiempo que produce un literal sin sangría, lo que se prefiere para la mayoría del código.
Sin embargo, una de las variaciones potenciales más interesantes es el uso de delimitadores `
(o ```
) para estos literales de cadena sin formato. Esto tendría varias ventajas:
- Evitaría todos los problemas con las cadenas que comienzan o terminan con comillas.
- Sería parecido al lenguaje markdown. Aunque eso en sí mismo no es potencialmente algo bueno, ya que los usuarios podrían esperar una interpretación de Markdown.
- Un literal de cadena sin formato solo tendría que empezar y terminar con un solo carácter en la mayoría de los casos, y solo necesitaría varios en el caso mucho más raro de contenidos que incluyan comillas inversas.
- Sería natural ampliar esto en el futuro con
```xml
, de nuevo similar a markdown. Sin embargo, por supuesto, eso también es cierto con el formato"""
.
Sin embargo, el beneficio neto aquí parece pequeño. En consonancia con la historia de C#, creo que "
debería continuar siendo el delimitador de string literal
, al igual que lo es para @""
y $""
.
Reuniones de diseño
Problemas abiertos para analizar Problemas resueltos:
- [x] ¿deberíamos tener un único formulario de línea? Técnicamente podríamos hacerlo sin él. Pero significaría que las cadenas simples que no contienen una nueva línea siempre tomarían al menos tres líneas. Es muy pesado forzar construcciones de una sola línea a ser de tres líneas solo para evitar escapes.
Decisión de diseño: Sí, tendremos un único formulario de línea.
- [x] ¿deberíamos exigir que una multilínea empiece con una nueva línea? Creo que deberíamos. También nos da la capacidad de apoyar elementos como
"""xml
en el futuro.
Decisión de diseño: Sí, se requerirá que una multilínea empiece con una nueva línea.
- [x] ¿debería realizarse la anulación de sangría automática? Creo que deberíamos. Hace que el código parezca mucho más agradable.
Decisión de diseño: Sí, se realizará la desdencación automática.
- [x] ¿deberíamos restringir que el espacio en blanco común mezcle tipos de espacios en blanco? No creo que deberíamos. De hecho, hay una estrategia de sangría común denominada "tabulación para sangría, espacio para la alineación". Sería muy natural usarlo para alinear el delimitador final con el delimitador inicial en un caso en el que el delimitador inicial no se inicie en una tabulación.
Decisión de diseño: no tendremos restricciones en la combinación de espacios en blanco.
- [x] ¿deberíamos usar otra cosa para las vallas?
`
coincidiría con la sintaxis de Markdown y significaría que no era necesario iniciar siempre estas cadenas con tres comillas. Bastaría uno para el caso común.
Decisión de diseño: usaremos """
- [x] ¿deberíamos tener un requisito de que el delimitador tenga más comillas que la secuencia de comillas más largas del valor de cadena? Técnicamente no es necesario. por ejemplo:
var v = """
contents"""""
"""
Se trata de una cadena con """
como delimitador. Varios miembros de la comunidad han declarado que esto es confuso y debemos requerir en un caso como este que el delimitador siempre tiene más caracteres. Eso sería:
var v = """"""
contents"""""
""""""
Decisión de diseño: Sí, el delimitador debe ser mayor que cualquier secuencia de comillas en la propia cadena.
C# feature specifications