$ หมายความว่าอะไรก่อนสตริง?


251

ฉันกำลังจะไปใช้สตริงคำต่อคำ แต่ฉันเข้าใจผิดพิมพ์แทน$@

แต่คอมไพเลอร์ไม่ได้ให้ฉันข้อผิดพลาดใด ๆ และรวบรวมสำเร็จ

ฉันต้องการที่จะรู้ว่ามันคืออะไรและมันทำอะไร ฉันค้นหามัน แต่ฉันไม่พบอะไรเลย

อย่างไรก็ตามมันไม่เหมือนสายอักขระคำต่อคำเพราะฉันไม่สามารถเขียน:

string str = $"text\";

ไม่มีใครรู้ว่าสิ่งที่$ก่อนที่สตริงยืนใน C #

string str = $"text";

ฉันใช้ Visual Studio 2015 CTP

คำตอบ:


419

$สั้นString.Formatและใช้กับการแก้ไขสตริงซึ่งเป็นคุณลักษณะใหม่ของ C # 6 ตามที่ใช้ในกรณีของคุณมันไม่ทำอะไรเลยเช่นเดียวกับที่string.Format()จะไม่ทำอะไรเลย

มันมาเป็นของตัวเองเมื่อใช้ในการสร้างสตริงที่มีการอ้างอิงถึงค่าอื่น ๆ สิ่งที่ต้องเขียนก่อนหน้านี้เป็น:

var anInt = 1;
var aBool = true;
var aString = "3";
var formated = string.Format("{0},{1},{2}", anInt, aBool, aString);

ตอนนี้กลายเป็น:

var anInt = 1;
var aBool = true;
var aString = "3";
var formated = $"{anInt},{aBool},{aString}";

นอกจากนี้ยังมีทางเลือก - รูปแบบของการประมาณค่าสตริงโดยใช้$@ (ลำดับของสัญลักษณ์ทั้งสองนั้นสำคัญ) มันช่วยให้คุณสมบัติของ@""สตริงที่จะผสมกับ$""เพื่อรองรับการแก้ไขสตริงโดยไม่จำเป็นต้อง\\ตลอดทั้งสายของคุณ ดังนั้นสองบรรทัดต่อไปนี้:

var someDir = "a";
Console.WriteLine($@"c:\{someDir}\b\c");

จะส่งออก:

c:\a\b\c

29
โปรดทราบว่ามันไม่ใช่การใช้ String.Format แต่เป็นคุณสมบัติที่คอมไพเลอร์ไม่ใช่เป็นรันไทม์
Shahar Prish

2
โน้ตเล็ก ๆ น้อย ๆ ที่ผมได้เรียนรู้ในวันนี้ถ้าคุณใช้$@แล้วคุณบังคับให้หนีตัวอักษรโดยใช้" กรณีนี้ไม่ได้เมื่อคุณจะใช้"" $
Flater

3
@ Flater ไม่มีส่วนเกี่ยวข้องกับสัญลักษณ์ $ นั่นเป็นพฤติกรรมแบบเดียวกันกับก่อนที่จะมีสัญลักษณ์ $ อยู่
BVernon

2
จนถึงจุดของคุณเกี่ยวกับการเรียงลำดับของสัญลักษณ์คำต่อคำ (@) และการแก้ไข ($) การเรียงลำดับเป็นสิ่งสำคัญการแก้ไขนี้จะถูกแก้ไขใน C # 8 เพื่อให้การสั่งซื้อไม่สำคัญอีกต่อไป ดู: devsanon.com/uncategorized/…
elkaz

39

มันสร้างสตริงหยัน

จากMSDN

ใช้ในการสร้างสตริง การแสดงออกของสตริง interpolated ดูเหมือนว่าสตริงแม่แบบที่มีการแสดงออก นิพจน์สตริงที่ถูกแทรกจะสร้างสตริงโดยการแทนที่นิพจน์ที่มีอยู่ด้วย ToString represenations ของผลลัพธ์ของนิพจน์

เช่น

 var name = "Sam";
 var msg = $"hello, {name}";

 Console.WriteLine(msg); // hello, Sam

คุณสามารถใช้นิพจน์ภายในสตริงที่สอดแทรก

 var msg = $"hello, {name.ToLower()}";
 Console.WriteLine(msg); // hello, sam

String.Formatสิ่งที่ดีเกี่ยวกับเรื่องนี้คือการที่คุณไม่จำเป็นต้องกังวลเกี่ยวกับคำสั่งของพารามิเตอร์ที่คุณทำกับ

  var s = String.Format("{0},{1},{2}...{88}",p0,p1,..,p88);

ตอนนี้ถ้าคุณต้องการลบพารามิเตอร์บางตัวคุณต้องไปและอัปเดตการนับทั้งหมดซึ่งไม่ใช่กรณีอีกต่อไป

โปรดทราบว่าดีเก่าstring.formatยังคงเกี่ยวข้องหากคุณต้องการระบุข้อมูลของคุณทางวัฒนธรรมในการจัดรูปแบบ


โปรดทราบว่าคุณสามารถอาจจะยังคงใช้$และระบุข้อมูลวัฒนธรรมถ้าคุณแปลงข้อมูลของคุณไปสตริงภายในของการแสดงออกโดยใช้วัฒนธรรมที่ถูกต้องเช่น$ {somevar.ToString(...,[Insert culture info here])}
jrh

18

รหัสตัวอย่าง

public class Person {
    public String firstName { get; set; }
    public String lastName { get; set; }
}

// Instantiate Person
var person = new Person { firstName = "Albert", lastName = "Einstein" };

// We can print fullname of the above person as follows
Console.WriteLine("Full-Name - " + person.firstName + " " + person.lastName);
Console.WriteLine("Full-Name - {0} {1}", person.firstName, person.lastName);
Console.WriteLine($"Full-Name - {person.firstName} {person.lastName}");

เอาท์พุต

Full-Name - Albert Einstein
Full-Name - Albert Einstein
Full-Name - Albert Einstein

มันเป็นInterpolated Strings คุณสามารถใช้สตริงที่สอดแทรกทุกที่ที่คุณสามารถใช้สตริงตามตัวอักษร เมื่อรันโปรแกรมของคุณจะรันโค้ดด้วยสตริงตัวอักษรที่สอดแทรกโค้ดจะคำนวณสตริงตัวอักษรใหม่โดยการประเมินนิพจน์การแก้ไข การคำนวณนี้เกิดขึ้นทุกครั้งที่โค้ดที่มีสตริงการประมวลผลดำเนินการ

ตัวอย่างต่อไปนี้สร้างค่าสตริงที่คำนวณค่าการแก้ไขสตริงทั้งหมด มันเป็นผลลัพธ์สุดท้ายและมีสตริงประเภท การเกิดวงเล็บปีกกาคู่(“{{“ and “}}”)ทั้งหมดจะถูกแปลงเป็นวงเล็บปีกกาเดี่ยว

string text = "World";
var message = $"Hello, {text}";

หลังจากเรียกใช้งานด้านบน 2 บรรทัดตัวแปรจะmessageมี "Hello, World"

Console.WriteLine(message); // Prints Hello, World

ข้อมูลอ้างอิง - MSDN


10

คุณสมบัติที่ยอดเยี่ยม ฉันแค่ต้องการชี้ให้เห็นความสำคัญว่าทำไมสิ่งนี้ถึงดีกว่า string.format หากบางคนไม่ชัดเจน

ฉันอ่านบางคนกำลังพูดว่า order string.format เป็น "{0} {1} {2}" เพื่อให้ตรงกับพารามิเตอร์ คุณไม่ได้ถูกบังคับให้สั่ง "{0} {1} {2}" ใน string.format คุณสามารถทำ "{2} {0} {1}" อย่างไรก็ตามหากคุณมีพารามิเตอร์จำนวนมากเช่น 20 คุณต้องการจัดลำดับสตริงเป็น "{0} {1} {1} {2} ... {19}" หากเป็นระเบียบแบบสับคุณจะมีช่วงเวลาที่ยากในการเรียงพารามิเตอร์ของคุณ

ด้วย $ คุณสามารถเพิ่มพารามิเตอร์แบบอินไลน์โดยไม่ต้องนับพารามิเตอร์ของคุณ ทำให้รหัสอ่านและบำรุงรักษาง่ายขึ้น

ข้อเสียของ $ คือคุณไม่สามารถทำซ้ำพารามิเตอร์ในสตริงได้อย่างง่ายดายคุณต้องพิมพ์มัน ตัวอย่างเช่นถ้าคุณเบื่อที่จะพิมพ์ System.Environment.NewLine คุณสามารถทำ string.format ("... {0} ... {0} ... {0}", System.Environment.NewLine), แต่ใน $ คุณต้องทำซ้ำ คุณไม่สามารถทำ $ "{0}" และส่งผ่านไปยัง string.format เนื่องจาก $ "{0}" ส่งคืน "0"

ในบันทึกด้านข้างฉันได้อ่านความคิดเห็นใน tpoic ที่ซ้ำกันอีกรายการ ฉันไม่สามารถแสดงความคิดเห็นดังนั้นที่นี่เป็น เขาพูดว่า

string msg = n + " sheep, " + m + " chickens";

สร้างวัตถุสตริงมากกว่าหนึ่งรายการ สิ่งนี้ไม่เป็นความจริง หากคุณทำสิ่งนี้ในบรรทัดเดียวมันจะสร้างเพียงหนึ่งสตริงและวางไว้ในแคชสตริง

1) string + string + string + string;
2) string.format()
3) stringBuilder.ToString()
4) $""

พวกเขาทั้งหมดส่งกลับสตริงและสร้างเพียงหนึ่งค่าในแคช

ในทางกลับกัน:

string+= string2;
string+= string2;
string+= string2;
string+= string2;

สร้าง 4 ค่าที่แตกต่างกันในแคชเนื่องจากมี 4 ";"

ดังนั้นจะเป็นการง่ายกว่าที่จะเขียนโค้ดดังต่อไปนี้ แต่คุณจะต้องสร้างสตริงที่สอดแทรกห้าบรรทัดเนื่องจาก Carlos Muñozแก้ไข:

string msg = $"Hello this is {myName}, " +
  $"My phone number {myPhone}, " +
  $"My email {myEmail}, " +
  $"My address {myAddress}, and " +
  $"My preference {myPreference}.";

สิ่งนี้จะสร้างสตริงเดียวในแคชในขณะที่คุณอ่านโค้ดได้ง่าย ฉันไม่แน่ใจเกี่ยวกับประสิทธิภาพการทำงาน แต่ฉันแน่ใจว่า MS จะปรับให้เหมาะสมถ้ายังไม่ได้ทำ


1
ตัวอย่างสุดท้ายของคุณผิด: จริง ๆ แล้วคุณกำลัง crating สองสาย: หนึ่งจากสาย interpolated และอื่น ๆ จากส่วนที่เหลือของสตริง โปรดสังเกตว่ามีเพียงรายการที่มี {myName} เท่านั้นที่ถูกแก้ไขส่วนที่เหลือไม่ทำงานอย่างที่คาดไว้
Carlos Muñoz

1
และถ้าคุณย่อหน้า $ กับ 5 สายมันก็จะสร้าง 5 สายหยันแต่ละคนมีของตัวเองแล้วตัดแบ่งที่รันไทม์กับString.Format() String.Concatดังนั้นจึงเป็นการดีกว่าที่คุณจะไม่แยกเป็นหลายบรรทัด
Carlos Muñoz

1
คุณพูดถูก @Carlos Muñozฉันได้แก้ไขแล้ว ขอบคุณสำหรับการจับความผิดพลาด
BoBoDev

8

โปรดทราบว่าคุณสามารถรวมสองสิ่งนี้เข้าด้วยกันซึ่งค่อนข้างเท่ห์ (แม้ว่ามันจะดูแปลก ๆ ):

// simple interpolated verbatim string
WriteLine($@"Path ""C:\Windows\{file}"" not found.");

5
หากเพียงแค่คุณสามารถตัดสินใจลำดับที่คุณพิมพ์หรือ$@ @$น่าเสียดายที่มันสามารถเป็นได้$@
Bauss

2
@Bauss นี่เหมาะสมแล้ว @กำหนดวิธีการแสดงสตริงตัวอักษร เป็นทางลัดสำหรับ$ string.Formatคิดว่ามันเป็น$(@"");
marsze

string.Formatมันไม่จริงทางลัดสำหรับ เป็นเรื่องหวานสำหรับการนำเสนอค่าที่แยกวิเคราะห์เป็น a string.Formatดังนั้นจึงมีเหตุผลบางส่วน แต่ไม่ใช่ทั้งหมด
Bauss

3
ฉันแค่บอกว่า$เป็นการเรียกใช้ฟังก์ชั่นโดยนัยในขณะที่@เป็นส่วนหนึ่งของตัวอักษรเช่นเดียวกับmในตัวอักษรทศนิยม นั่นเป็นเหตุผลที่มีเพียงหนึ่งคำสั่งตรรกะ
marsze

2
ฉันรู้ว่าส่วนใหญ่เป็นเพียงที่นี่เพื่อแสดงให้เห็น$แต่เพื่อความเข้ากันได้สูงสุดและไม่เข้ารหัสยากว่าตัวคั่นไดเรกทอรีเป็น '/' หรือ '\' และยังหลีกเลี่ยงความผิดพลาดอย่างหลีกเลี่ยงไม่ได้ทำให้เกิดการทับสองครั้ง มีอยู่แล้วฉันขอแนะนำให้ใช้Path.Combine()แทนการใช้การต่อสตริงเมื่อทำงานกับไดเรกทอรีและไฟล์
jrh

6

สะดวกกว่า string จัดรูปแบบและคุณสามารถใช้ intellisense ได้ที่นี่เช่นกัน

ป้อนคำอธิบายรูปภาพที่นี่

และนี่คือวิธีทดสอบของฉัน:

[TestMethod]
public void StringMethodsTest_DollarSign()
{
    string name = "Forrest";
    string surname = "Gump";
    int year = 3; 
    string sDollarSign = $"My name is {name} {surname} and once I run more than {year} years."; 
    string expectedResult = "My name is Forrest Gump and once I run more than 3 years."; 
    Assert.AreEqual(expectedResult, sDollarSign);
}

6

มันหมายถึงการแก้ไขสตริง

มันจะปกป้องคุณเพราะมันคือการเพิ่มการป้องกันเวลารวบรวมในการประเมินสตริง

คุณจะไม่ได้รับข้อยกเว้นอีกต่อไป string.Format("{0}{1}",secondParamIsMissing)


6

ตัวอย่างต่อไปนี้จะเน้นถึงข้อดีต่าง ๆ ของการใช้สตริงที่แทรกเข้ามาstring.Format()จนถึงความสะอาดและการอ่าน นอกจากนี้ยังแสดงให้เห็นว่าโค้ดภายใน{}ได้รับการประเมินเช่นเดียวกับอาร์กิวเมนต์ของฟังก์ชันอื่นเช่นเดียวกับที่string.Format()เราเรียก

using System;

public class Example
{
   public static void Main()
   {
      var name = "Horace";
      var age = 34;
      // replaces {name} with the value of name, "Horace"
      var s1 = $"He asked, \"Is your name {name}?\", but didn't wait for a reply.";
      Console.WriteLine(s1);

      // as age is an integer, we can use ":D3" to denote that
      // it should have leading zeroes and be 3 characters long
      // see https://docs.microsoft.com/en-us/dotnet/standard/base-types/how-to-pad-a-number-with-leading-zeros
      //
      // (age == 1 ? "" : "s") uses the ternary operator to 
      // decide the value used in the placeholder, the same 
      // as if it had been placed as an argument of string.Format
      //
      // finally, it shows that you can actually have quoted strings within strings
      // e.g. $"outer { "inner" } string"
      var s2 = $"{name} is {age:D3} year{(age == 1 ? "" : "s")} old.";
      Console.WriteLine(s2); 
   }
}
// The example displays the following output:
//       He asked, "Is your name Horace?", but didn't wait for a reply.
//       Horace is 034 years old.

6

$ ไวยากรณ์ดี แต่มีข้อเสียเดียว

หากคุณต้องการอะไรเช่นเทมเพลตสตริงที่มีการประกาศในระดับชั้นเป็นฟิลด์ ... และอยู่ในที่เดียวที่ควรจะเป็น

จากนั้นคุณต้องประกาศตัวแปรในระดับเดียวกัน ... ซึ่งไม่เจ๋งจริงๆ

มันดีกว่าการใช้สตริงรูปแบบไวยากรณ์สำหรับสิ่งนี้

class Example1_StringFormat {
 string template = $"{0} - {1}";

 public string FormatExample1() {
   string some1 = "someone";
   return string.Format(template, some1, "inplacesomethingelse");
 }

 public string FormatExample2() {
   string some2 = "someoneelse";
   string thing2 = "somethingelse";
   return string.Format(template, some2, thing2);
 }
}

การใช้งานของ globals ไม่ได้โอเคและนอกเหนือจากนั้น - มันไม่ทำงานกับ globals เช่นกัน

 static class Example2_Format {
 //must have declaration in same scope
 static string some = "";
 static string thing = "";
 static string template = $"{some} - {thing}";

//This returns " - " and not "someone - something" as you would maybe 
//expect
 public static string FormatExample1() {
   some = "someone";
   thing = "something";
   return template;
 }

//This returns " - " and not "someoneelse- somethingelse" as you would 
//maybe expect
 public static string FormatExample2() {
   some = "someoneelse";
   thing = "somethingelse";
   return template;
 }
}

คำตอบนี้มีความสำคัญเนื่องจากมันชี้ให้เห็นว่าการแก้ไขเกิดขึ้นเมื่อคุณ "เรียก" $ string ไม่ใช่เมื่อคุณประกาศ
dx_over_dt

1
คุณถูกต้องเกี่ยวกับรูปแบบการต่อต้านของการประกาศตัวแปรการประมาณค่าของคุณที่ขอบเขตของคลาสอย่างไรก็ตามหากตัวแปรเหล่านั้นเป็นของคุณสมบัติคลาสแล้วรูปแบบนี้จะทำงานได้ดี
dx_over_dt

@dx_over_dt คุณผิด สตริง Interpolated จะถูกประเมินในเวลาที่ประกาศ นั่นเป็นเหตุผลว่าทำไมโค้ดตัวอย่างไม่สมเหตุสมผล มันจะไม่รวบรวม
Nineberry

@NberryBerry คุณถูกต้องทั้งคู่เกี่ยวกับสตริง interpolated จะถูกประเมินในเวลาที่พวกเขาประกาศและเกี่ยวกับตัวอย่าง _ $ รูปแบบไม่ได้รวบรวมและเกี่ยวกับรหัสตัวอย่างทำให้รู้สึกไม่ :) ฉันแก้ไขตัวอย่างเพื่ออธิบายได้ดีขึ้น
Tom

5

ฉันไม่รู้ว่ามันทำงานอย่างไร แต่คุณสามารถใช้มันเพื่อแท็บค่าของคุณ!

ตัวอย่าง:

Console.WriteLine($"I can tab like {"this !", 5}.");

แน่นอนคุณสามารถแทนที่ "สิ่งนี้!" ด้วยตัวแปรใด ๆ หรืออะไรก็ตามที่มีความหมายเช่นเดียวกับที่คุณสามารถเปลี่ยนแท็บ


ใช่คุณยังสามารถจัดรูปแบบสตริงmsdn.microsoft.com/en-us/library/dn961160.aspx
M.kazem Akhgary

0

$ sign ในสตริงใช้สำหรับนิยามของสตริงการแก้ไขที่เป็นคุณลักษณะใน C # เพื่อสอดแทรกสตริงเป็น "สตริงที่แท้จริง" ที่อาจมีนิพจน์ที่ถูกแทรก

สำหรับข้อมูลเพิ่มเติมนี่คือแหล่งที่มาของคำตอบและตัวอย่าง: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.