生文字列リテラル
手記
この記事は機能仕様です。 仕様は、機能の設計ドキュメントとして機能します。 これには、提案された仕様の変更と、機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が最終決定され、現在の ECMA 仕様に組み込まれるまで公開されます。
機能の仕様と完成した実装の間には、いくつかの違いがある可能性があります。 これらの違いは、関連する 言語設計会議 (LDM) ノートでキャプチャされます。
機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。
チャンピオンの課題: https://github.com/dotnet/csharplang/issues/8647
概要
文字列リテラルの新しい形式を許可します。文字列リテラルは、3 つ以上の """
文字 (ただし、最大値なし) で始まり、必要に応じて new_line
、文字列の内容が続き、リテラルが開始したのと同じ数の引用符で終わります。 例えば:
var xml = """
<element attr="content"/>
""";
入れ子になったコンテンツ自体が """
を使用する場合があるため、開始/終了区切り記号は次のように長くなる可能性があります。
var xml = """"
Ok to use """ here
"""";
開発者がコードで好きなインデントを読みやすくするために、これらの文字列リテラルは、最終的なリテラル値を生成するときに最後の行で指定されたインデントを自然に削除します。 たとえば、フォームのリテラルは次のようになります。
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
次の内容が含まれます。
<element attr="content">
<body>
</body>
</element>
これにより、コードは自然に見える一方で、必要なリテラルを生成し、特殊な文字列操作ルーチンを使用する必要がある場合は実行時コストを回避できます。
インデントの動作が望ましくない場合は、次のように無効にすることも簡単です。
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
1 行のフォームもサポートされています。 3 つ以上の """
文字で始まり (ただし上限はなし)、その後に文字列の内容 (new_line
文字を含めることはできません)、リテラルが開始されたのと同じ数の引用符で終わります。 例えば:
var xml = """<summary><element attr="content"/></summary>""";
補間された生の文字列もサポートされています。 この場合、文字列は補間を開始するために必要な中かっこの数を指定します (リテラルの先頭に存在するドル記号の数によって決まります)。 それよりも少ない中括弧を含む中括弧シーケンスは単にコンテンツとして扱われます。 例えば:
var json = $$"""
{
"summary": "text",
"length" : {{value.Length}},
};
""";
モチベーション
C# には、任意のテキストを実質的に含むことができる単純な文字列リテラルを作成する一般的な方法がありません。 現在、すべての C# 文字列リテラル 形式では、コンテンツで特殊文字が使用される場合 (常に区切り記号が使用されている場合) には、何らかの形式のエスケープが必要です。 これにより、リテラルに他の言語 (XML、HTML、JSON リテラルなど) が含まれるのを簡単に防ぐことができます。
現在、C# でこれらのリテラルを形成するすべての現在のアプローチでは、ユーザーは常にコンテンツを手動でエスケープする必要があります。 その時点での編集は、エスケープを回避することができず、コンテンツで発生するたびに対処する必要があるため、非常に面倒に感じることがあります。 特に引用符やバックスラッシュが含まれている場合、これは正規表現で特に面倒になります。 逐語的 (@""
) 文字列を使用する場合でも、引用符自体をエスケープする必要があるため、C# と正規表現が混在することになります。 {
と }
は、補間された ($""
) 文字列でも同様にイライラします。
問題の核心は、すべての文字列に固定の開始/終了区切り記号があるということです。 そうである限り、文字列の内容にはその終了区切り記号を指定する必要があるため、エスケープメカニズムが常に必要になります。 これは、区切り記号 "
が多くの言語で非常に一般的であるため、特に問題になります。
これに対処するために、この提案では、文字列の内容と競合しない方法でいつでも作成できるように、柔軟な開始区切り記号と終了区切り記号を使用できます。
目標
- エスケープ シーケンスをまったく必要とせずに、すべての文字列値をユーザーが提供できるメカニズムを提供します。 すべての文字列はエスケープ シーケンスなしで表現できる必要があるため、ユーザーがテキストコンテンツと競合しないことが保証される区切り記号を常に指定できる必要があります。
- 同じ方法で補間をサポートします。 上記のように、すべての 文字列はエスケープなしで表現できる必要があるため、ユーザーは常にテキストコンテンツと競合しないことを保証する
interpolation
区切り記号を指定できる必要があります。 重要なのは、補間 区切り文字 ({
と}
) を使用する言語は、一流のものであり、使用するのが辛くないと感じる必要があります。 - 複数行の文字列リテラルはコード内で快適に見える必要があり、コンパイル ユニット内のインデントが奇妙に見えるべきではありません。 重要なのは、インデントのないリテラル値は、コードのフローを分割し、それを囲む残りのコードと一致しないように見えるので、ファイルの最初の列を強制的に占有しないようにする必要があります。
- この動作は、リテラルを明確にして読みやすくしながら、簡単にオーバーライドできる必要があります。
- すべての文字列について、それ自体に
new_line
を含んでいない、または引用符 ("
) 文字で始まらず、終わらない場合、その文字列リテラル自体を1行で表現することが可能である必要があります。- 必要に応じて、複雑さを増して、次のように調整できます。それ自体に
new_line
が含まれていないすべての文字列 (引用符"
文字で開始または終了できる) には、文字列リテラル自体を 1 行で表すことができます。 詳細については、「Drawbacks
」セクションの拡張された提案を参照してください。
- 必要に応じて、複雑さを増して、次のように調整できます。それ自体に
詳細な設計 (非補間の場合)
次の形式で新しい string_literal
運用環境を追加します。
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>
;
raw_string_literal
の終了区切り記号は、開始区切り記号と一致する必要があります。 したがって、開始区切り記号が """""
場合、終了区切り記号も同様である必要があります。
raw_string_literal
の上記の文法は、次のように解釈する必要があります。
- 少なくとも 3 つの引用符で始まります (ただし、引用符の上限はありません)。
- 次に、開始引用符と同じ行の内容で続行されます。 同じ行にあるこれらの内容は、空白または非空白であることができます。 'blank' は '完全に空白' と同義です。
- 同じ行の内容が空白でない場合は、それ以上のコンテンツをフォローできません。 つまり、リテラルは、同じ行で同じ数の引用符で終わる必要があります。
- 同じ行の内容が空白の場合、リテラルは
new_line
といくつかの後続のコンテンツ行とnew_line
で続行できます。- コンテンツ行は、
new_line
を除く任意のテキストです。 - その後、
new_line
で終わり、続いていくつか (場合によっては 0) のwhitespace
があり、そのリテラルが開始した時と同じ数の引用符が続きます。
- コンテンツ行は、
生文字列リテラル値
開始 raw_string_literal_delimiter
と終了 raw_string_literal_delimiter
の間の部分は、次の方法で raw_string_literal
の値を形成するために使用されます。
single_line_raw_string_literal
の場合、リテラルの値は、開始raw_string_literal_delimiter
と終了の間の内容になります。multi_line_raw_string_literal
の場合、最初のwhitespace* new_line
と最後のnew_line whitespace*
は文字列の値の一部ではありません。 ただし、raw_string_literal_delimiter
ターミナルの前の最後のwhitespace*
部分は 'インデント空白' と見なされ、他の行の解釈方法に影響します。- 最終的な値を取得するには、
(raw_content | new_line)*
のシーケンスをウォークし、次の処理を実行します。new_line
場合は、new_line
の内容が最終的な文字列値に追加されます。- 空白の
raw_content
でない場合 (つまり、not_new_line+
にwhitespace
以外の文字が含まれている場合):- 'インデント空白' は、
raw_content
のプレフィックスである必要があります。 それ以外の場合はエラーです。 - 'インデント空白' は
raw_content
の先頭から削除され、残りは最終的な文字列値に追加されます。
- 'インデント空白' は、
- それが「空白」の
raw_content
である場合(つまり、not_new_line+
は完全にwhitespace
)。- 'インデント空白' は、
raw_content
のプレフィックスである必要があります。または、raw_content
は 'インデント空白' のプレフィックスである必要があります。 それ以外の場合はエラーです。 - 'インデント空白' の多くは
raw_content
の先頭から削除され、残りはすべて最終的な文字列値に追加されます。
- 'インデント空白' は、
説明:
single_line_raw_string_literal
では、new_line
値を持つ文字列を表す機能はありません。single_line_raw_string_literal
は、'インデントの空白' トリミングには含まれません。 その値は常に、開始区切り記号と終了区切り記号の間の正確な文字です。multi_line_raw_string_literal
が最後のコンテンツ行の最後のnew_line
を無視するため、次の文字列は開始new_line
がなく、終了new_line
もありません。
var v1 = """
This is the entire content of the string.
""";
これにより、開始 new_line
が無視される方法と対称性が維持され、"インデントの空白" を常に調整できるようにする統一された方法も提供されます。 ターミナル new_line
文字列を表すには、次のように余分な行を指定する必要があります。
var v1 = """
This string ends with a new line.
""";
single_line_raw_string_literal
は引用符 ("
) で始まる文字列値を表すことはできませんが、サポートされる方法を示すDrawbacks
セクションでは、この提案の拡張が提供されています。multi_line_raw_string_literal
は、最初のraw_string_literal_delimiter
に続くwhitespace* new_line
で始まります。 区切り記号の後のこのコンテンツは完全に無視され、文字列の値を決定する際には使用されません。 これにより、コンテンツが"
文字自体で始まるraw_string_literal
を指定するメカニズムが可能になります。 例えば:
var v1 = """
"The content of this string starts with a quote
""";
raw_string_literal
は、引用符 ("
) で終わるコンテンツを表すこともできます。 これは、終端の区切り記号を独自の行に置く必要がある場合にサポートされます。 例えば:
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""
""";
- 'blank'
raw_content
は 'インデント空白' の接頭辞であるか、または 'インデント空白' が 'blank'raw_content
の接頭辞である必要があります。これは、空白文字が混在することによる混乱を防ぐのに役立ちます。特に、その行で何が起こるべきかが不明確になるのを防ぎます。 たとえば、次のケースは無効です。
var v1 = """
Start
<tab>
End
""";
ここで、「インデントの空白」は 9 文字の空白文字ですが、空白の
raw_content
はそのプレフィックスで始まるわけではありません。 その<tab>
行をどのように扱うべきかについての明確な答えはありません。 無視する必要がありますか? それは.........<tab>
と同じである必要がありますか? そのため、それを違法にすることは、混乱を避けるために最も明確に思えます。ただし、次のケースは有効であり、同じ文字列を表します。
var v1 = """
Start
<four spaces>
End
""";
var v1 = """
Start
<nine spaces>
End
""";
どちらの場合も、「インデントの空白」は 9 つのスペースになります。 どちらの場合も、そのプレフィックスのできるだけ多くを削除し、各ケースの "空白" raw_content
を空にします (すべての new_line
をカウントするわけではありません)。 これにより、ユーザーはこれらの行をコピー/貼り付けや編集する際に、それらの行にある空白を見たり、気にしたりする必要がなくなります。
- 次の場合:
var v1 = """
Start
<ten spaces>
End
""";
「インデントの空白」はそのまま 9 つのスペースになります。 ただし、ここでは可能な限り多くの 'インデント空白' を削除し、"空白" raw_content
は最終的なコンテンツに 1 つのスペースを提供します。 これにより、コンテンツに保持すべき空白文字が必要な場合に、これらの行をそのままにできます。
- 以下は技術的には適していません。
var v1 = """
""";
これは、生の文字列の先頭に new_line
が必要ですが、末尾にも new_line
が必要であるためです (そうでない場合)。 最小限の法的 raw_string_literal
は次のとおりです。
var v1 = """
""";
しかし、この文字列は ""
に相当するため、決して面白くないです。
インデントの例
'インデント空白' アルゴリズムは、次のような複数の入力で視覚化できます。 次の例では、垂直バー文字 |
を使用して、結果の生文字列の最初の列を示します。
例 1 - 標準ケース
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
は次のように解釈されます。
var xml = """
|<element attr="content">
| <body>
| </body>
|</element>
""";
例 2 - コンテンツと同じ行で区切り記号を終了します。
var xml = """
<element attr="content">
<body>
</body>
</element>""";
これは違法です。 最後のコンテンツ行は、new_line
で終わる必要があります。
例 3 - 終了区切り記号が開始区切り記号の前にある例
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
は次のように解釈されます。
var xml = """
| <element attr="content">
| <body>
| </body>
| </element>
""";
例 4 - 開始区切り記号の後の終了区切り記号
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
これは違法です。 コンテンツの行は、'インデントの空白' で始まる必要があります
例 5 - 空の空白行
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
は次のように解釈されます。
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
例 6 - プレフィックスよりも空白が少ない空白行 (ドットはスペースを表します)
var xml = """
<element attr="content">
<body>
</body>
....
</element>
""";
は次のように解釈されます。
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
例 7 - プレフィックスよりも空白が多い空白行 (ドットはスペースを表します)
var xml = """
<element attr="content">
<body>
</body>
..............
</element>
""";
は次のように解釈されます。
var xml = """
|<element attr="content">
| <body>
| </body>
|....
|</element>
""";
詳細な設計 (補間ケース)
通常の補間文字列 ($"..."
など) の補間は、現在、{
文字を使用して interpolation
を開始し、{{
エスケープ シーケンスを使用して実際のオープン ブレース文字を挿入する方法でサポートされています。 この同じメカニズムを使用すると、この提案の目標 '1' と '2' に違反します。 コア文字として {
を持つ言語 (JavaScript、JSON、Regex、埋め込みC# など) では、エスケープする必要が生じ、未加工の文字列リテラルの目的が失われます。
補間をサポートするために、通常の $"
補間文字列とは異なる方法で補間を導入します。 具体的には、interpolated_raw_string_literal
は数個の $
文字で始まります。 これらのカウントは、interpolation
を区切るためにリテラルの内容に必要な {
(および }
) 文字の数を示します。 重要なのは、中かっこのエスケープメカニズムが依然として存在しないことです。 むしろ、引用符 ("
) と同様に、リテラル自体は常に、文字列の残りのコンテンツと競合しないことが確実な補間の区切り記号を指定できます。 たとえば、補間ホールを含む JSON リテラルは、次のように記述できます。
var v1 = $$"""
{
"orders":
[
{ "number": {{order_number}} }
]
}
"""
ここでは、{{...}}
は、$$
区切り記号プレフィックスで指定された 2 つの中かっこの必要な数と一致します。 1 つの $
の場合、補間は通常の補間文字列リテラルである {...}
の場合と同様に指定されます。 重要なのは、これは、N
$
文字を持つ補間リテラルに、(行内の同じ型の) 2*N-1
中かっこのシーケンスを持つことができることを意味します。 最後の N
中かっこは補間処理を開始 (または終了) し、残りの N-1
中かっこは単なるコンテンツとして扱われます。 例えば:
var v1 = $$"""X{{{1+1}}}Z""";
この場合、内側の2つの{{
と}}
の波括弧はインターポレーションに属し、外側の単一の波括弧は単にコンテンツです。 したがって、上記の文字列はコンテンツ X{2}Z
に相当します。 2*N
(またはそれ以上) の中かっこを持つことは常にエラーです。 中かっこのシーケンスを内容として長くするには、状況に応じて $
文字の数を増やす必要があります。
補間された生の文字列リテラルは、次のように定義されます。
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.
;
上記は raw_string_literal
の定義に似ていますが、いくつかの重要な違いがあります。 interpolated_raw_string_literal
は次のように解釈する必要があります。
- 少なくとも 1 ドル記号 (ただし上限なし) で始まり、次に 3 つの引用符 (上限なし) で始まります。
- 次に、開始引用符と同じ行のコンテンツを続行します。 同じ行のこのコンテンツは空白にすることも、空白以外にすることもできます。 'blank' は '完全に空白' と同義です。
- 同じ行のコンテンツが空白でない場合は、それ以上のコンテンツをフォローできません。 つまり、リテラルは、同じ行で同じ数の引用符で終わる必要があります。
- 同じ行の内容が空白の場合、リテラルは
new_line
といくつかの後続のコンテンツ行とnew_line
で続行できます。- コンテンツ行は、
new_line
を除く任意のテキストです。 - コンテンツラインには、任意の位置に複数の
raw_interpolation
出現箇所を含めることができます。raw_interpolation
は、リテラルの先頭にあるドル記号の数と同じ数の開き中かっこ ({
) で始まらなければなりません。 - 'インデントの空白' が空でない場合、
raw_interpolation
はすぐにnew_line
の後に続くことはできません。 raw_interpolation
は §12.8.3で指定された通常の規則に従います。 すべてのraw_interpolation
は、ドル記号と開き中かっこの数と同じ数の閉じ中かっこ (}
) で終わる必要があります。- すべての
interpolation
は、通常のverbatim_string_literal
(@""
) のinterpolation
と同様に、新しい改行を含めることができます。 - その後、
new_line
で終わり、続いていくつか (場合によっては 0) のwhitespace
があり、そのリテラルが開始した時と同じ数の引用符が続きます。
- コンテンツ行は、
補間された文字列値の計算は、通常の raw_string_literal
と同じ規則に従います。ただし、raw_interpolation
を含む行を処理するように更新される点が異なります。 文字列値の構築は、補間ホールが実行時に生成される値に置き換えられるだけで、同じ方法で行われます。 interpolated_raw_string_literal
が FormattableString
に変換された場合、補間の値はそれぞれの順序で arguments
配列から FormattableString.Create
に渡されます。 すべての行から「インデントの空白」が削除されたinterpolated_raw_string_literal
後の残りのコンテンツは、raw_interpolation
が発生した各場所 (または、interpolation
の形式が expression ',' constant_expression
の場合は {N,constant}
) に適切な番号が付けられた {N}
コンテンツを除いて、FormattableString.Create
に渡される format
文字列を生成するために使用されます。
上記の仕様にはあいまいさがあります。 具体的には、テキスト内の {
のセクションと補間の {
が隣接する場合です。 例えば:
var v1 = $$"""
{{{order_number}}}
"""
これは、{{ {order_number } }}
または { {{order_number}} }
として解釈できます。 しかし、前者は違法であるため(c#式は {
で始まる可能性はありません)、そのように解釈するのは無意味です。 したがって、最も内側の {
と }
の中かっこが補間を形成し、最も外側の中かっこがテキストを形成する後者の方法で解釈します。 将来的には、中かっこで囲まれた式が言語でサポートされている場合、これは問題になる可能性があります。 ただし、その場合は、次のようなケースを記述することをお勧めします:{{({some_new_expression_form})}}
. ここでは、かっこを使用して、リテラル/補間の残りから式の部分を区切ることができます。 これには、補間の書式設定/位置合わせ指定子 ({(x ? y : z)}
など) と競合しないように 3 項条件式をラップするという前例があります。
欠点
生の文字列リテラルは、言語の複雑さを増します。 既に多数の目的のために、多くの文字列リテラル フォームが既に存在しています。 ""
文字列、@""
文字列、および $""
文字列には、既に多くの能力と柔軟性があります。 しかし、それらはすべてエスケープする必要のない生コンテンツを提供する方法を欠いています。
上記の規則では、4.aの場合はサポートされていません。
- ...
- 必要に応じて、複雑さを増して、次のように調整できます。それ自体に
new_line
が含まれていないすべての文字列 (引用符"
文字で開始または終了できる) には、文字列リテラル自体を 1 行で表すことができます。
- 必要に応じて、複雑さを増して、次のように調整できます。それ自体に
これは、区切り記号自体ではなく、開始引用符または終了引用符 ("
) がコンテンツに属する必要があることを知る手段がないためです。 これがサポートする必要がある重要なシナリオである場合は、並列 '''
コンストラクトを追加して、"""
フォームと一緒に進むことができます。 その並列コンストラクトを使用すると、"
で開始および終了する 1 行の文字列を、並列コンストラクト """'This string starts and ends with apostrophes'"""
と共に '''"This string starts and ends with quotes"'''
として簡単に記述できます。 これは、引用符文字を視覚的に分離するのに役立つ場合もあります。これは、主に 1 つの引用符文字を他よりもはるかに多く使用する言語を埋め込むときに役立つ可能性があります。
選択肢
https://github.com/dotnet/csharplang/discussions/89 では、多くのオプションについて説明します。 選択肢は数多くありますが、複雑さと人間工学の不十分さにあまりにも迷いを感じます。 この方法では、文字列の内容との競合が心配されない限り、開始/終了引用符の長さを増やし続けるだけのシンプルさを選択します。 また、記述したコードはインデントが適切に表示され、ほとんどのコードが必要とするインデント解除リテラルを生成することもできます。
ただし、最も興味深い潜在的なバリエーションの 1 つは、これらの生の文字列リテラルに `
(または ```
) フェンスを使用することです。 これにはいくつかの利点があります。
- 引用符で終わる文字列に関するすべての問題を回避できます。
- マークダウンに似ているように見えるでしょう。 ユーザーがマークダウンの解釈を期待する可能性があるため、それ自体は良いことではありません。
- 生の文字列リテラルは、ほとんどの場合、1 文字で開始および終了するだけでよく、バックティック自体を含むコンテンツの非常にまれなケースでは複数しか必要ありません。
```xml
で将来的にこれを拡張することは自然に感じるでしょう, 再びマークダウンに近い. しかし、もちろん、それは"""
形式にも当てはまります。
しかし、全体的に、ここでの純利益は小さいようです。 C# の履歴に従って、"
@""
と $""
の場合と同様に、引き続き string literal
区切り記号である必要があると思います。
デザイン会議
議論すべき未解決の問題 解決された問題:
- [x] 1 行のフォームが必要ですか? 私たちは技術的にそれなしで行うことができます。 しかし、改行を含まない単純な文字列は常に少なくとも3行かかることを意味します。 私は、単一のライン コンストラクトをエスケープを避けるために 3 行に強制することは非常に重いことだと思います。
設計上の決定: はい、1 行のフォームが作成されます。
- [x] 複数行を改行で始める必要がありますか? 私たちはそうすべきだと思います。 また、将来的に
"""xml
などをサポートする機能も提供します。
設計の判断: はい、複数行は改行で始める必要があります
- [x] 自動歯切りを行う必要がありますか? 私たちはそうすべきだと思います。 コードがより見た目に美しくなります。
設計上の決定: はい、自動インデント解除が行われます。
- [x] 共通の空白文字で異なる空白タイプの混在を制限すべきですか? 私たちはすべきだとは思わない。 実際、「インデントにはタブを、配置にはスペースを使う」という一般的な戦略があります。 開始区切り記号がタブストップから始まらない場合、終了区切り記号を開始区切り記号に合わせるためにこれを使用することは極めて自然です。
設計上の決定: 空白の混在に制限はありません。
- [x] フェンスに何か他のものを使用する必要がありますか?
`
はマークダウン構文と一致し、これらの文字列を常に 3 つの引用符で始める必要がなかったことを意味します。 一般的なケースでは、1 つだけで十分です。
設計上の決定: """
を使用します
- [x] 区切り記号に文字列値内の引用符の最も長いシーケンスよりも多くの引用符が含まれている必要がありますか? 技術的には必須ではありません。 例えば:
var v = """
contents"""""
"""
これは、区切り記号として """
を持つ文字列です。 複数のコミュニティ メンバーが、これは混乱していると述べ、このような場合は、区切り記号に常により多くの文字が含まれている必要があります。 その後、次のようになります。
var v = """"""
contents"""""
""""""
設計上の決定: はい。区切り記号は、文字列自体の引用符のシーケンスよりも長くする必要があります。
C# feature specifications