คุณสมบัติที่ซ่อนของ C #? [ปิด]


1475

สิ่งนี้อยู่ในใจของฉันหลังจากฉันเรียนรู้จากคำถามนี้ :

where T : struct

พวกเราผู้พัฒนา C # ทุกคนรู้พื้นฐานของ C # ฉันหมายถึงการประกาศเงื่อนไขเงื่อนไขลูปตัวดำเนินการ ฯลฯ

พวกเราบางคนเข้าใจสิ่งต่าง ๆ เช่นGenerics , ประเภทนิรนาม , lambdas , LINQ , ...

แต่คุณสมบัติหรือลูกเล่นที่ซ่อนอยู่ของ C # ที่แม้แต่แฟน C #, ผู้ติดยา, ผู้เชี่ยวชาญแทบจะไม่รู้คืออะไร?

นี่คือคุณสมบัติที่เปิดเผยแล้ว:


คำสำคัญ

คุณลักษณะ

วากยสัมพันธ์

  • ??(รวมตัวกันเป็นโมฆะ ) โอเปอเรเตอร์โดยkokos
  • การตีธงหมายเลขโดยNick Berardi
  • where T:newโดยLars Mæhlum
  • ข้อมูลทั่วไปโดยนัยโดยKeith
  • lambdas หนึ่งพารามิเตอร์โดยKeith
  • คุณสมบัติอัตโนมัติโดยKeith
  • นามแฝง Namespace โดยKeith
  • ตัวอักษรของคำต่อท้ายสตริงด้วย @ โดยPatrick
  • enumค่าโดยlfoust
  • @variablenames โดยmarxidad
  • eventผู้ประกอบการโดยmarxidad
  • จัดรูปแบบวงเล็บสตริงโดยPortman
  • ตัวดัดแปลงการเข้าถึงการเข้าถึงคุณสมบัติโดยxanadont
  • ผู้ประกอบการ?:ตามเงื่อนไข (ที่ประกอบไปด้วย) ( ) โดยJasonS
  • checkedและuncheckedผู้ประกอบการโดยBinoj Antony
  • implicit and explicitผู้ประกอบการโดยFlory

คุณสมบัติทางภาษา

คุณสมบัติของ Visual Studio

  • เลือกบล็อคข้อความในโปรแกรมแก้ไขโดยHimadri
  • ตัวอย่างโดยDannySmurf

กรอบ

วิธีการและคุณสมบัติ

  • String.IsNullOrEmpty()วิธีการโดยKiwiBastard
  • List.ForEach()วิธีการโดยKiwiBastard
  • BeginInvoke(), EndInvoke()วิธีการโดยจะคณบดี
  • Nullable<T>.HasValueและNullable<T>.ValueคุณสมบัติโดยRismo
  • GetValueOrDefaultวิธีการโดยJohn Sheehan

เคล็ดลับ & เทคนิค

  • วิธีการที่ดีสำหรับตัวจัดการเหตุการณ์โดยAndreas HR Nilsson
  • การเปรียบเทียบตัวพิมพ์ใหญ่โดยJohn
  • เข้าถึงประเภทที่ไม่ระบุตัวตนโดยไม่มีการสะท้อนกลับโดยdp
  • วิธีที่รวดเร็วในการยกตัวอย่างคุณสมบัติการรวบรวมโดยWill
  • ฟังก์ชั่นอินไลน์แบบไม่ระบุชื่อเหมือน JavaScript โดยroosteronacid

อื่น ๆ

คำตอบ:


752

นี่ไม่ใช่ C # ต่อ se แต่ฉันไม่ได้เห็นใครที่ใช้จริงๆSystem.IO.Path.Combine()เท่าที่ควร อันที่จริงคลาส Path ทั้งหมดนั้นมีประโยชน์จริง ๆ แต่ไม่มีใครใช้เลย!

ฉันยินดีที่จะเดิมพันว่าแอปที่ใช้งานจริงทุกตัวมีรหัสต่อไปนี้ถึงแม้ว่ามันจะไม่ควร:

string path = dir + "\\" + fileName;

584

lambdas และการอนุมานชนิดมีการประเมินค่าต่ำเกินไป แลมบ์ดาสามารถมีหลายข้อความและพวกเขาเป็นสองเท่าในฐานะตัวแทนวัตถุที่เข้ากันได้โดยอัตโนมัติ (ตรวจสอบให้แน่ใจว่าลายเซ็นตรงกัน) ใน:

Console.CancelKeyPress +=
    (sender, e) => {
        Console.WriteLine("CTRL+C detected!\n");
        e.Cancel = true;
    };

โปรดทราบว่าฉันไม่ได้มีnew CancellationEventHandlerหรือฉันต้องระบุประเภทsenderและeพวกเขาจะอนุมานได้จากเหตุการณ์ นี่คือเหตุผลว่าทำไมการเขียนทั้งหมดจึงมีความยุ่งยากน้อยกว่าdelegate (blah blah)ซึ่งคุณต้องระบุประเภทของพารามิเตอร์ด้วย

แลมบัลดัสไม่จำเป็นต้องส่งคืนสิ่งใดและการอนุมานประเภทมีประสิทธิภาพอย่างยิ่งในบริบทเช่นนี้

และ BTW คุณสามารถส่งคืนแลมบ์ดาที่ทำให้แลมบ์ดามีความสามารถในการตั้งโปรแกรมได้ ตัวอย่างเช่นนี่คือแลมบ์ดาที่สร้างแลมบ์ดาที่จัดการกับเหตุการณ์ Button.Click:

Func<int, int, EventHandler> makeHandler =
    (dx, dy) => (sender, e) => {
        var btn = (Button) sender;
        btn.Top += dy;
        btn.Left += dx;
    };

btnUp.Click += makeHandler(0, -1);
btnDown.Click += makeHandler(0, 1);
btnLeft.Click += makeHandler(-1, 0);
btnRight.Click += makeHandler(1, 0);

หมายเหตุการผูกมัด: (dx, dy) => (sender, e) =>

นี่คือเหตุผลที่ฉันมีความสุขที่ได้เรียนการเขียนโปรแกรมฟังก์ชั่น :-)

นอกเหนือจากพอยน์เตอร์ใน C ฉันคิดว่านี่เป็นสิ่งพื้นฐานอื่น ๆ ที่คุณควรเรียนรู้ :-)


528

จากRick Strahl :

คุณสามารถโยง ?? โอเปอเรเตอร์เพื่อให้คุณสามารถทำการเปรียบเทียบเป็นโมฆะ

string result = value1 ?? value2 ?? value3 ?? String.Empty;

454

ชื่อสามัญนามแฝง:

using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>;

จะช่วยให้คุณใช้แทนASimpleNameDictionary<string, Dictionary<string, List<string>>>

ใช้มันเมื่อคุณจะใช้สิ่งที่มีขนาดใหญ่ยาวซับซ้อนเหมือนกันในหลาย ๆ ที่


438

จากCLR ผ่าน C # :

เมื่อสตริง normalizing ก็ขอแนะนำให้คุณใช้ ToUpperInvariant แทน ToLowerInvariant เพราะไมโครซอฟท์มีการเพิ่มประสิทธิภาพรหัสสำหรับการดำเนินการเปรียบเทียบตัวพิมพ์ใหญ่

ฉันจำครั้งหนึ่งที่ผู้ร่วมงานของฉันเปลี่ยนสตริงเป็นตัวพิมพ์ใหญ่เสมอก่อนที่จะเปรียบเทียบ ฉันสงสัยอยู่เสมอว่าทำไมเขาถึงทำอย่างนั้นเพราะฉันรู้สึกว่า "เป็นธรรมชาติ" มากกว่าที่จะเปลี่ยนเป็นตัวพิมพ์เล็กก่อน หลังจากอ่านหนังสือตอนนี้ฉันรู้ว่าทำไม


254
เมื่อคุณ "แปลงสตริงเป็นตัวพิมพ์ใหญ่" คุณสร้างวัตถุสตริงชั่วคราวตัวที่สอง ฉันคิดว่าการเปรียบเทียบแบบนี้ไม่เป็นที่ต้องการนั่นเป็นวิธีที่ดีที่สุดคือ: String.Equals (stringA, stringB, StringComparison.CurrentCultureIgnoreCase) whcih ไม่ได้สร้างสตริงการทิ้งนี้เลย
แอนโธนี

32
คุณสามารถเพิ่มประสิทธิภาพประเภทใดในการเปรียบเทียบสตริงตัวพิมพ์ใหญ่ที่ไม่สามารถทำได้กับสตริงตัวพิมพ์เล็ก ฉันไม่เข้าใจว่าทำไมคนหนึ่งถึงดีกว่าอีกคนหนึ่ง
Parappa

36
การแปลงเป็นตัวพิมพ์ใหญ่แทนที่จะเป็นตัวพิมพ์เล็กสามารถป้องกันพฤติกรรมที่ไม่ถูกต้องในบางวัฒนธรรมได้ ตัวอย่างเช่นในภาษาตุรกีแผนที่สองตัวพิมพ์เล็กของ i เป็นตัวพิมพ์ใหญ่เดียวกัน I. Google "ตุรกี i" สำหรับรายละเอียดเพิ่มเติม
Neil

34
ฉันพยายามเปรียบเทียบ ToUpperInvariant กับ ToLowerInvariant ฉันไม่พบความแตกต่างในประสิทธิภาพการทำงานภายใต้. NET 2.0 หรือ 3.5 แน่นอนว่าไม่ใช่ทุกสิ่งที่รับประกัน "แนะนำอย่างยิ่ง" โดยใช้อย่างใดอย่างหนึ่ง
Rasmus Faber

19
ToUpperInvariant เป็นที่ต้องการเพราะมันทำให้ตัวละครทุกตัวไปกลับ ดูmsdn.microsoft.com/en-us/library/bb386042.aspx สำหรับการเปรียบเทียบเขียน"a".Equals("A", StringComparison.OrdinalIgnoreCase)
SLaks

408

เคล็ดลับที่ฉันโปรดปรานคือการใช้ตัวดำเนินการรวมศูนย์และวงเล็บเพื่อสร้างตัวอย่างให้ฉันโดยอัตโนมัติ

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }

23
คุณหาอ่านยากไหม
Riri

72
มันยากที่จะอ่านเล็กน้อยสำหรับ noo ... เอ่อไม่มีประสบการณ์ แต่มันมีขนาดกะทัดรัดและมีสองรูปแบบและคุณสมบัติภาษาที่โปรแกรมเมอร์ควรรู้และเข้าใจ ดังนั้นในขณะที่มันยากในตอนแรกมันให้ประโยชน์ของการเป็นเหตุผลในการเรียนรู้

38
Lazy instantiation ค่อนข้างจะเป็นการทุจริตเพราะเป็นทางเลือกที่ดีของมนุษย์ที่จะหลีกเลี่ยงการคิดค่าคงที่ในชั้นเรียน นอกจากนี้ยังมีปัญหาการทำงานพร้อมกัน
John Leidegren

17
ฉันได้รับแจ้งเสมอว่านี่เป็นแนวปฏิบัติที่ไม่ดีการเรียกคุณสมบัติไม่ควรทำอะไรเช่นนี้ หากคุณมีชุดที่นั่นและตั้งค่าเป็นโมฆะมันจะแปลกมากสำหรับคนที่ใช้ API ของคุณ
Ian

8
@Joel ยกเว้นว่าการตั้งค่า ListOfFoo เป็นโมฆะไม่ได้เป็นส่วนหนึ่งของสัญญาการเรียนและไม่เป็นวิธีปฏิบัติที่ดี นั่นเป็นเหตุผลที่ไม่มีตัวตั้งค่า นอกจากนี้ยังเป็นเหตุผลว่าทำไม ListOfFoo จึงรับประกันการส่งคืนคอลเลกชันและไม่เป็นโมฆะ มันเป็นเรื่องแปลกมากที่ถ้าคุณทำสิ่งเลวร้ายสองอย่าง (สร้างตัวเซ็ตเตอร์และตั้งค่าคอลเลกชันเป็นโมฆะ) สิ่งนี้จะส่งผลให้ความคาดหวังของคุณผิด ฉันจะไม่แนะนำให้ทำ Environment.Exit () ใน getter เช่นกัน แต่นั่นก็ไม่เกี่ยวข้องกับคำตอบนี้

315

หลีกเลี่ยงการตรวจสอบตัวจัดการเหตุการณ์ null

การเพิ่มผู้รับมอบสิทธิ์ที่ว่างลงในเหตุการณ์เมื่อมีการประกาศระงับความจำเป็นที่จะต้องตรวจสอบเหตุการณ์เพื่อหาค่าว่างก่อนที่จะเรียกมันว่ายอดเยี่ยม ตัวอย่าง:

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

ให้คุณทำสิ่งนี้

public void DoSomething()
{
    Click(this, "foo");
}

แทนที่จะเป็นแบบนี้

public void DoSomething()
{
    // Unnecessary!
    MyClickHandler click = Click;
    if (click != null) // Unnecessary! 
    {
        click(this, "foo");
    }
}

โปรดดูการสนทนาที่เกี่ยวข้องและบล็อกโพสต์นี้โดย Eric Lippert ในหัวข้อนี้ (และข้อเสียที่เป็นไปได้)


87
ฉันเชื่อว่าปัญหาจะปรากฏขึ้นหากคุณพึ่งพาเทคนิคนี้แล้วคุณจะต้องทำให้เป็นอันดับชั้น คุณจะกำจัดเหตุการณ์และจากนั้นในการดีซีเรียลไลเซชันคุณจะได้รับ NullRefference .... ดังนั้นคุณสามารถติดกับ "วิธีการแบบเก่า" ในการทำสิ่งต่าง ๆ มันปลอดภัยกว่า
sirrocco

16
คุณยังคงสามารถตั้งค่าตัวจัดการเหตุการณ์ของคุณเป็นโมฆะเพื่อให้คุณยังคงได้รับการอ้างอิงเป็นโมฆะและคุณยังคงมีสภาพการแข่งขัน
Robert Paulson

64
การทดสอบโปรไฟล์ด่วนแสดงให้เห็นว่าตัวจัดการเหตุการณ์ที่บอกรับสมาชิกที่ไม่มีการทดสอบว่างจะใช้เวลาประมาณ 2 เท่าของเวลาของตัวจัดการเหตุการณ์ที่ไม่ได้สมัครรับการทดสอบด้วย null Multicast event handler ที่ไม่มีการทดสอบ null ใช้เวลาประมาณ 3.5 เท่าของการจัดการเหตุการณ์ singlecast ด้วยการทดสอบ null
Paddy พ่อ

54
วิธีนี้จะช่วยหลีกเลี่ยงความจำเป็นในการตรวจสอบแบบ null โดยเพียงแค่มีผู้สมัครสมาชิกด้วยตนเอง แม้ว่าจะเป็นเหตุการณ์ที่ว่างเปล่า แต่ก็มีค่าใช้จ่ายที่คุณไม่ต้องการ หากไม่มีสมาชิกที่คุณไม่ต้องการเริ่มกิจกรรมเลยไม่ควรเริ่มต้นเหตุการณ์จำลองที่ว่างเปล่าเสมอ ฉันจะพิจารณารหัสที่ไม่ดีนี้
Keith

56
นี่เป็นข้อเสนอแนะที่แย่มากด้วยเหตุผลในความคิดเห็นข้างต้น หากคุณต้องทำให้โค้ดของคุณดู "สะอาด" ให้ใช้วิธีการขยายเพื่อตรวจสอบค่า null จากนั้นเรียกใช้เหตุการณ์ ผู้ที่มีสิทธิ์แก้ไขควรเพิ่มข้อเสียในคำตอบนี้อย่างแน่นอน
เกร็ก

305

ทุกอย่างอื่นรวมทั้ง

1) generics โดยนัย (ทำไมต้องใช้วิธีการเท่านั้นและไม่ได้เรียน)

void GenericMethod<T>( T input ) { ... }

//Infer type, so
GenericMethod<int>(23); //You don't need the <>.
GenericMethod(23);      //Is enough.

2) lambdas ง่าย ๆ ด้วยพารามิเตอร์เดียว:

x => x.ToString() //simplify so many calls

3) ประเภทและผู้เริ่มต้นที่ไม่ระบุชื่อ:

//Duck-typed: works with any .Add method.
var colours = new Dictionary<string, string> {
    { "red", "#ff0000" },
    { "green", "#00ff00" },
    { "blue", "#0000ff" }
};

int[] arrayOfInt = { 1, 2, 3, 4, 5 };

อีกหนึ่ง:

4) คุณสมบัติอัตโนมัติสามารถมีขอบเขตที่แตกต่างกัน:

public int MyId { get; private set; }

ขอบคุณ @pcomcoman สำหรับการเตือนฉัน:

5) นามแฝง Namespace (ไม่ใช่ว่าคุณต้องการความแตกต่างนี้):

using web = System.Web.UI.WebControls;
using win = System.Windows.Forms;

web::Control aWebControl = new web::Control();
win::Control aFormControl = new win::Control();

14
ใน # 3 คุณสามารถทำ Enumerable.Range (1,5)
Echostorm

18
ฉันคิดว่าคุณสามารถเริ่มต้นอาร์เรย์ด้วย int [] nums = {1,2,3}; ตั้งแต่ 1.0 :) ไม่ต้องการแม้แต่คำหลัก "ใหม่"
ลูคัส

13
แลมบ์ดาโดยไม่มีพารามิเตอร์ () => DoSomething ();
Pablo Retyk

5
ฉันใช้ทั้งสอง {รับ; ชุดภายใน } และ {รับ; ชุดป้องกัน } ดังนั้นรูปแบบนี้สอดคล้องกัน
Keith

7
@ Kirk Broadhurst - ถูกต้อง - new web.Control()สามารถใช้งานได้ในตัวอย่างนี้ ::กองกำลังไวยากรณ์มันในการรักษาคำนำหน้าเป็นชื่อแทน namespace เพื่อให้คุณสามารถมีระดับที่เรียกว่าwebและweb::Controlไวยากรณ์จะยังคงทำงานในขณะที่web.Controlไวยากรณ์จะไม่ทราบว่าจะตรวจสอบชั้นเรียนหรือการ namespace เนื่องจากว่าฉันมักจะใช้::เมื่อทำนามแฝง namespace
Keith

286

ฉันไม่ทราบคำหลัก "เป็น" มาระยะหนึ่งแล้ว

MyClass myObject = (MyClass) obj;

VS

MyClass myObject = obj as MyClass;

อันที่สองจะคืนค่าว่างหาก obj ไม่ใช่ MyClass แทนที่จะส่งข้อยกเว้นการส่งคลาส


42
อย่าทำมากเกินไป ผู้คนจำนวนมากดูเหมือนจะใช้เป็นเพราะชอบไวยากรณ์แม้ว่าพวกเขาต้องการความหมายของ (ToType) x
Scott Langham

4
ฉันไม่เชื่อว่ามันให้ประสิทธิภาพที่ดีกว่า คุณทำโปรไฟล์หรือไม่ (แน่นอนว่ามันไม่เมื่อโยนล้มเหลว ... แต่เมื่อคุณใช้ (MyClass) โยนความล้มเหลวเป็นพิเศษ .. และหายากมาก (ถ้าพวกเขาเกิดขึ้นในทุก) ดังนั้นจึงทำให้ไม่แตกต่าง.
สกอตต์แลงแฮม

7
นี่เป็นสิ่งที่มีประสิทธิภาพมากกว่าหากกรณีปกติคือการส่งสัญญาณไม่สำเร็จ มิฉะนั้นวัตถุ cast โดยตรง (ประเภท) จะเร็วขึ้น การโยนโดยตรงโดยตรงใช้เวลานานกว่าในการโยนยกเว้นเพื่อส่งคืนค่าว่าง
Spence

15
ขวาไปตามบรรทัดเดียวกันของคำหลัก "เป็น" ... คำหลัก "เป็น" มีประโยชน์เช่นเดียวกับ
dkpatt

28
คุณสามารถละเมิดได้และมี NullReferenceException ตามถนนของคุณในภายหลังเมื่อคุณมี InvalidCastException ก่อนหน้านี้
Andrei Rînea

262

สองสิ่งที่ฉันชอบคือคุณสมบัติอัตโนมัติเพื่อให้คุณสามารถยุบรหัสของคุณลงไปอีก:

private string _name;
public string Name
{
    get
    {
        return _name;
    }
    set
    {
        _name = value;
    }
}

กลายเป็น

public string Name { get; set;}

ด้วยวัตถุเริ่มต้น:

Employee emp = new Employee();
emp.Name = "John Smith";
emp.StartDate = DateTime.Now();

กลายเป็น

Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}

6
ควรสังเกตว่าคุณสมบัติอัตโนมัติเป็นคุณสมบัติ C # 3.0 เท่านั้นหรือไม่
Jared Updike

21
มีการแนะนำคุณสมบัติอัตโนมัติด้วยคอมไพเลอร์ 3.0 แต่เนื่องจากคอมไพเลอร์สามารถตั้งค่าเป็นเอาท์พุทรหัส 2.0 พวกเขาทำงานได้ดี อย่าพยายามคอมไพล์โค้ด 2.0 ด้วยคุณสมบัติอัตโนมัติในคอมไพเลอร์รุ่นเก่า!
Joshua Shannon

74
สิ่งที่หลายคนไม่ทราบก็คือการได้รับและการตั้งค่าสามารถมีการเข้าถึงที่แตกต่างกันเช่น: ชื่อสตริงสาธารณะ {รับ ชุดส่วนตัว;}
Nader Shirazie

7
ปัญหาเฉพาะของคุณสมบัติอัตโนมัติคือดูเหมือนว่าจะไม่สามารถให้ค่าเริ่มต้นได้
Stein Åsmul

7
@ ANeves: ไม่เลย จากหน้านั้น: DefaultValueAttribute จะไม่ทำให้สมาชิกเริ่มต้นโดยอัตโนมัติด้วยค่าของคุณสมบัติ คุณต้องตั้งค่าเริ่มต้นในรหัสของคุณ [DefaultValue]ใช้สำหรับนักออกแบบดังนั้นจึงรู้ได้ว่าจะแสดงคุณสมบัติเป็นตัวหนา (หมายถึงไม่ใช่ค่าเริ่มต้น)
Roger Lipscombe

255

คำหลัก 'เริ่มต้น' ในประเภททั่วไป:

T t = default(T);

ผลลัพธ์เป็น 'null' ถ้า T เป็นประเภทการอ้างอิงและ 0 ถ้าเป็น int, false ถ้าเป็นบูลีนและอื่น ๆ


4
บวก: พิมพ์? เป็นทางลัดสำหรับ Nullable <type> default (int) == 0 แต่ default (int?) == null
กันแดด


221

@ บอกคอมไพเลอร์เพื่อละเว้นอักขระเลี่ยงใด ๆ ในสตริง

แค่อยากจะอธิบายเรื่องนี้ ... มันไม่ได้บอกให้เพิกเฉยกับตัวละครหนีมันบอกให้คอมไพเลอร์แปลความหมายเป็นตัวอักษร

ถ้าคุณมี

string s = @"cat
             dog
             fish"

มันจะพิมพ์ออกมาเป็นจริง (โปรดทราบว่ามันยังมีช่องว่างที่ใช้สำหรับการเยื้อง):

cat
             dog
             fish

สตริงจะไม่รวมช่องว่างทั้งหมดที่คุณใช้สำหรับการเยื้องหรือไม่
andy

18
ใช่มันเรียกว่าสตริงคำต่อคำ
Joan Venge

4
มันจะมีความชัดเจนมากขึ้นถ้าผลลัพธ์แสดงช่องว่างที่จะพิมพ์ออกมาเช่นกัน ตอนนี้ดูเหมือนว่าตัวละครบรรทัดใหม่จะถูกพิมพ์ แต่ช่องว่างจะถูกละเว้น
aleemb

มีประโยชน์มากสำหรับการหลีกเลี่ยงนิพจน์ปกติและแบบสอบถาม SQL แบบยาว
ashes999

นอกจากนี้ยังมีแผนที่{{จะ{และ}}จะทำให้มันมีประโยชน์สำหรับ} string.Format()
Ferruccio

220

ผมคิดว่าหนึ่งในที่สุดภายใต้การชื่นชมและคุณลักษณะที่ไม่ค่อยมีคนรู้จักของ C # (NET 3.5) เป็นExpression ต้นไม้ , โดยเฉพาะอย่างยิ่งเมื่อรวมกับยาสามัญและ Lambdas นี่เป็นวิธีการในการสร้าง API ที่ไลบรารีใหม่เช่น NInject และ Moq กำลังใช้งานอยู่

ตัวอย่างเช่นสมมติว่าฉันต้องการลงทะเบียนวิธีด้วย API และ API นั้นต้องได้รับชื่อวิธี

รับคลาสนี้:

public class MyClass
{
     public void SomeMethod() { /* Do Something */ }
}

ก่อนหน้านี้มันเป็นเรื่องธรรมดามากที่จะเห็นนักพัฒนาทำสิ่งนี้ด้วยสตริงและประเภท (หรืออย่างอื่นที่ใช้สตริงเป็นหลัก):

RegisterMethod(typeof(MyClass), "SomeMethod");

นั่นมันแย่เพราะไม่มีพิมพ์ดีด ถ้าฉันเปลี่ยนชื่อ "SomeMethod" เป็นอย่างไร อย่างไรก็ตามใน 3.5 ฉันสามารถทำสิ่งนี้ในแบบที่พิมพ์ออกมาอย่างรุนแรง:

RegisterMethod<MyClass>(cl => cl.SomeMethod());

ซึ่งคลาส RegisterMethod ใช้Expression<Action<T>>ดังนี้:

void RegisterMethod<T>(Expression<Action<T>> action) where T : class
{
    var expression = (action.Body as MethodCallExpression);

    if (expression != null)
    {
        // TODO: Register method
        Console.WriteLine(expression.Method.Name);
    }
}

นี่เป็นเหตุผลสำคัญอย่างหนึ่งที่ฉันหลงรัก Lambdas และ Expression Trees ตอนนี้


3
ฉันมีระดับสาธารณูปโภคสะท้อนที่ไม่เหมือนกันกับ FieldInfo, PropertyInfo ฯลฯ ...
Olmo

ใช่มันเยี่ยมมาก ฉันสามารถใช้วิธีการเช่นนี้ในการเขียนรหัสเช่นEditValue(someEmployee, e => e.FirstName);ในตรรกะทางธุรกิจของฉันและให้มันสร้างตรรกะการประปาทั้งหมดสำหรับ ViewModel และ View เพื่อแก้ไขคุณสมบัตินั้นโดยอัตโนมัติ (เช่นป้ายกำกับที่มีข้อความ "ชื่อ" และกล่องข้อความด้วย การเชื่อมโยงที่เรียก setter ของคุณสมบัติ FirstName เมื่อผู้ใช้แก้ไขชื่อและอัพเดตมุมมองโดยใช้ getter) นี่น่าจะเป็นพื้นฐานสำหรับ DSL ภายในใหม่ส่วนใหญ่ใน C #
Scott Whitlock

4
ฉันคิดว่าสิ่งเหล่านี้ไม่ค่อยเป็นที่รู้จักเท่าไรนัก
Justin Morgan

ทำไมคุณต้องลงทะเบียนวิธีการ? ฉันไม่เคยใช้สิ่งนี้มาก่อน - จะใช้สิ่งนี้ที่ไหนและเมื่อใด
MoonKnight

209

" ผลผลิต " จะมาถึงใจของฉัน แอตทริบิวต์บางอย่างเช่น[DefaultValue ()]ก็เป็นหนึ่งในรายการโปรดของฉัน

"การvar " คำหลักที่เป็นที่รู้จักกันมากขึ้นอีกนิด แต่ที่คุณสามารถใช้มันใน .NET 2.0 การใช้งานเช่นกัน (ตราบใดที่คุณใช้ NET 3.5 คอมไพเลอร์และตั้งค่าการส่งออกรหัส 2.0) ดูเหมือนจะไม่เป็นที่รู้จักมาก ดี.

แก้ไข: kokos ขอบคุณสำหรับการชี้ให้เห็น ?? ผู้ประกอบการที่มีประโยชน์จริงๆ เพราะมันเป็นบิตยากที่จะ google มัน (ตาม ?? ถูกละเว้นเพียง) นี่คือหน้าเอกสารประกอบของ MSDN สำหรับผู้ประกอบการที่: ?? ผู้ประกอบการ (อ้างอิง C #)


14
เอกสารค่าเริ่มต้นบอกว่ามันไม่ได้เป็นการตั้งค่าของคุณสมบัติ มันเป็นเพียงผู้ช่วยสำหรับนักสร้างภาพและผู้สร้างรหัส
Boris Callens

2
สำหรับ DefaultValue: ในระหว่างนี้บางไลบรารีใช้ ASP.net MVC ใช้ค่าเริ่มต้นบนพารามิเตอร์ของการกระทำการควบคุม (ซึ่งมีประโยชน์มากสำหรับประเภทที่ไม่เป็นโมฆะ) แน่นอนว่านี่คือตัวสร้างโค้ดเนื่องจากค่าไม่ได้ถูกกำหนดโดยคอมไพเลอร์ แต่ด้วยรหัสของ MVC
Michael Stum

6
ชื่อสำหรับ ?? ตัวดำเนินการคือตัวดำเนินการ "Null Coalescing"
Armstrongest

ผลผลิตเป็นที่ชื่นชอบผู้ประกอบการรวมกันอยู่ที่นั่นแม้ว่า ฉันไม่เห็นอะไรเกี่ยวกับ CAS หรือการลงนามในการชุมนุมชื่อที่แข็งแกร่ง GAC ... ฉันคิดว่าเฉพาะ CAS คือ C # ... แต่นักพัฒนาจำนวนมากจึงไม่มีเงื่อนงำเกี่ยวกับความปลอดภัย
BrainSlugs83

198

ฉันมักจะพบว่านักพัฒนา C # ส่วนใหญ่ไม่รู้ประเภท 'nullable' โดยพื้นฐานแล้วดั้งเดิมที่สามารถมีค่า Null

double? num1 = null; 
double num2 = num1 ?? -100;

ตั้งค่า double ที่สามารถ null ได้, num1 , เป็น null จากนั้นตั้ง double ปกติ, num2 , เป็นnum1หรือ-100ถ้าnum1เป็น null

http://msdn.microsoft.com/en-us/library/1t3y8s4s(VS.80).aspx

อีกอย่างหนึ่งเกี่ยวกับประเภท Nullable:

DateTime? tmp = new DateTime();
tmp = null;
return tmp.ToString();

มันเป็นผลตอบแทน String.Empty ตรวจสอบลิงค์นี้สำหรับรายละเอียดเพิ่มเติม


1
DateTime ไม่สามารถตั้งค่าเป็น null ได้
Jason Jackson

2
ถ้าอย่างนั้นก็คือ "int" เพียงแค่ C # น้ำตาลซินแทติกติกสำหรับ System.Int32? จริงๆแล้วมีการสนับสนุนคอมไพเลอร์ที่สร้างขึ้นรอบ ๆ ประเภท Nullable ทำให้สามารถตั้งค่าให้เป็นโมฆะ (ซึ่งไม่สามารถทำได้โดยใช้โครงสร้างทั่วไปเพียงอย่างเดียว) และต่อยมวยเป็นประเภทพื้นฐาน
P Daddy

4
@P Daddy - ใช่ int คือน้ำตาลประโยคสำหรับ System.Int32 พวกมันสามารถใช้แทนกันได้อย่างสมบูรณ์เหมือนกับ int? === Int32? === Nullable <Int32> === Nullable <int>
cjk

6
@ck: ใช่ int เป็นชื่อแทนของ System.Int32 ในชื่อ T? เป็นนามแฝงสำหรับ Nullable <T> แต่มันไม่ได้เป็นเพียงแค่วากยสัมพันธ์น้ำตาล มันเป็นส่วนหนึ่งของภาษาที่กำหนดไว้ นามแฝงไม่เพียง แต่ทำให้โค้ดอ่านง่ายขึ้น แต่ยังทำให้โมเดลของเราพอดียิ่งขึ้น แสดง Nullable <Double> เป็นสองเท่าได้หรือไม่ ขีดเส้นใต้มุมมองที่ค่าที่มีอยู่จึงเป็น (หรืออาจ) คู่ไม่ใช่แค่โครงสร้างทั่วไปบางอย่างที่สร้างอินสแตนซ์บน Type Double (ต่อ)
Paddy

3
... ไม่ว่าในกรณีใดข้อโต้แย้งไม่ได้เกี่ยวกับนามแฝง (นั่นเป็นเพียงการเปรียบเทียบที่ไม่ดีฉันคิดว่า) แต่ประเภทที่ไม่สามารถใช้ได้ - การใช้ไวยากรณ์ใด ๆ ก็ตามที่คุณต้องการ - เป็นคุณลักษณะทางภาษา คุณไม่สามารถทำซ้ำฟังก์ชันการทำงานทั้งหมดของ nullables (เปรียบเทียบกับ / มอบหมายของ null การส่งต่อผู้ประกอบการมวยประเภทพื้นฐานหรือ null เข้ากันได้กับการรวมกันเป็นโมฆะและasผู้ประกอบการ) กับ generics เพียงอย่างเดียว Nullable <T> เพียงอย่างเดียวนั้นเป็นพื้นฐานและห่างไกลจากตัวเอก แต่แนวคิดของประเภท nullable ซึ่งเป็นส่วนหนึ่งของภาษาคือเตะตูด
Paddy พ่อ

193

นี่คือฟีเจอร์ C # ที่ซ่อนอยู่ที่น่าสนใจในรูปแบบของคีย์เวิร์ด C # ที่ไม่มีเอกสาร:

__makeref

__reftype

__refvalue

__arglist

คำเหล่านี้เป็นคำหลัก C # ที่ไม่มีเอกสาร (แม้แต่ Visual Studio รู้จักคำเหล่านั้น!) ซึ่งถูกเพิ่มเข้ามาเพื่อการชกมวย / unboxing ที่มีประสิทธิภาพมากขึ้นก่อนที่จะมีชื่อสามัญ พวกเขาทำงานประสานงานกับโครงสร้าง System.TypedReference

นอกจากนี้ยังมี __arglist ซึ่งใช้สำหรับรายการพารามิเตอร์ความยาวผันแปร

สิ่งหนึ่งที่ผู้คนไม่ค่อยรู้มากนักคือSystem.WeakReference - คลาสที่มีประโยชน์มากที่ติดตามวัตถุ แต่ยังอนุญาตให้ผู้รวบรวมขยะสามารถรวบรวมได้

คุณสมบัติ "ซ่อน" ที่มีประโยชน์มากที่สุดคือคีย์เวิร์ด return return มันไม่ได้ซ่อนจริงๆ แต่มีคนมากมายไม่รู้เกี่ยวกับมัน LINQ ถูกสร้างขึ้นบนยอดนี้; จะช่วยให้แบบสอบถามที่ดำเนินการล่าช้าโดยการสร้างเครื่องรัฐภายใต้ประทุน เรย์มอนด์เฉินเพิ่งโพสต์เกี่ยวกับภายในรายละเอียดทราย


2
รายละเอียดเพิ่มเติมเกี่ยวกับคำหลักที่ไม่มีเอกสารโดยปีเตอร์ Bromberg ฉันยังไม่ได้รับถ้ามีเหตุผลที่จะใช้พวกเขา
HuBeZa

@ HuBeZa กับการกำเนิดของ generics มีเหตุผลดีๆมากมายที่จะใช้ __refType, __makeref และ __refvalue สิ่งเหล่านี้ถูกใช้เป็นหลักเพื่อหลีกเลี่ยงการชกมวยก่อนหน้า generics ใน. NET 2
ยูดาห์กาเบรียล Himango

Matt ด้วยการแนะนำ generics ใน. NET 2 มีเหตุผลเพียงเล็กน้อยที่จะใช้คำหลักเหล่านี้เนื่องจากวัตถุประสงค์ของพวกเขาคือเพื่อหลีกเลี่ยงการชกมวยเมื่อต้องรับมือกับประเภทของค่า ดูลิงค์ของ HuBeZa และดูcodeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#ud
Judah Gabriel Himango

185

ยูเนี่ยน (ประเภทหน่วยความจำแบบ C ++ ที่ใช้ร่วมกัน) อย่างแท้จริงปลอดภัย C #

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

[StructLayout(LayoutKind.Explicit)]
public class A
{
    [FieldOffset(0)]
    public byte One;

    [FieldOffset(1)]
    public byte Two;

    [FieldOffset(2)]
    public byte Three;

    [FieldOffset(3)]
    public byte Four;

    [FieldOffset(0)]
    public int Int32;
}

คุณสามารถปรับเปลี่ยนค่าของฟิลด์ไบต์ได้โดยจัดการฟิลด์ Int32 และในทางกลับกัน ตัวอย่างเช่นโปรแกรมนี้:

    static void Main(string[] args)
    {
        A a = new A { Int32 = int.MaxValue };

        Console.WriteLine(a.Int32);
        Console.WriteLine("{0:X} {1:X} {2:X} {3:X}", a.One, a.Two, a.Three, a.Four);

        a.Four = 0;
        a.Three = 0;
        Console.WriteLine(a.Int32);
    }

ผลลัพธ์นี้:

2147483647
FF FF FF 7F
65535

เพียงเพิ่มการใช้ System.Runtime.InteropServices;


7
@ George ทำงานอย่างมหัศจรรย์เมื่อคุณสื่อสารกับแอพรุ่นเก่าผ่านซ็อกเก็ตโดยใช้การประกาศสหภาพยูเนี่ยน
scottm

2
นอกจากนี้ยังมีความหมายที่จะบอกว่า int และ float ที่ offset 0 มันเป็นสิ่งที่คุณต้องการถ้าคุณต้องการจัดการตัวเลขจุดลอยตัวเป็นบิตมาสก์ซึ่งบางครั้งคุณต้องการ โดยเฉพาะถ้าคุณต้องการเรียนรู้สิ่งใหม่เกี่ยวกับตัวเลขจุดลอยตัว
John Leidegren

2
สิ่งที่น่ารำคาญเกี่ยวกับเรื่องนี้คือถ้าคุณจะใช้นี่คือโครงสร้างคอมไพเลอร์จะบังคับให้คุณตั้งค่าตัวแปรทั้งหมดในฟังก์ชั่น init ดังนั้นถ้าคุณมี: public A (int int32) {Int32 = int32; } มันจะขว้าง "Field 'One' จะต้องได้รับมอบหมายอย่างสมบูรณ์ก่อนที่การควบคุมจะถูกส่งกลับไปยังผู้โทร" ดังนั้นคุณต้องตั้งค่าหนึ่ง = สอง = สาม = สี่ = 0; เช่นกัน
manixrock

2
สิ่งนี้มีการใช้งานส่วนใหญ่กับข้อมูลไบนารี ฉันใช้โครงสร้าง "Pixel" กับ int32 @ 0 และสี่ไบต์สำหรับส่วนประกอบทั้งสี่ที่ 0, 1, 2 และ 3 เหมาะสำหรับการจัดการข้อมูลรูปภาพอย่างรวดเร็วและง่ายดาย
snarf

57
คำเตือน: วิธีการนี้ไม่ได้คำนึงถึงความ endianness นั่นหมายความว่ารหัส C # ของคุณจะไม่ทำงานเหมือนกันในทุกเครื่อง บนซีพียูน้อย endian (ที่เก็บไบต์ที่สำคัญน้อยที่สุดก่อน) พฤติกรรมที่แสดงจะถูกนำมาใช้ แต่สำหรับซีพียูขนาดใหญ่นั้นไบต์จะออกมาตรงกันข้ามกับที่คุณคาดไว้ ระวังวิธีที่คุณใช้ในรหัสการผลิต - รหัสของคุณอาจไม่สามารถพกพาไปยังอุปกรณ์พกพาและฮาร์ดแวร์อื่น ๆ และอาจแตกในรูปแบบที่ไม่ชัดเจน (เช่นไฟล์สองไฟล์ในรูปแบบเดียวกัน แต่จริง ๆ แล้วกลับคำสั่งไบต์)
เรย์เบิร์นส์

176

ใช้ @ สำหรับชื่อตัวแปรที่เป็นคำหลัก

var @object = new object();
var @string = "";
var @if = IpsoFacto(); 

38
ทำไมคุณต้องการใช้คำหลักเป็นชื่อตัวแปร ดูเหมือนว่าฉันนี้จะทำให้รหัสน้อยอ่านและ obfuscated
Jon

41
ด้วยเหตุผลที่ว่ามี CLI นั้นต้องการสำหรับการทำงานร่วมกันกับภาษาอื่นที่อาจใช้คำสำคัญ C # เป็นชื่อสมาชิก
Mark Cidade

69
หากคุณต้องการใช้ตัวช่วย HTML ของ asp.net MVC และกำหนดคลาส HTML คุณจะมีความสุขที่รู้ว่าคุณสามารถใช้ @ class ดังนั้นมันจะไม่ถูกจดจำเป็นคำหลักของคลาส
Boris Callens

31
เหมาะสำหรับวิธีการขยาย คงโมฆะสาธารณะ DoSomething (นี่บาร์ @this สตริง foo) { ... }
โจนาธาน C ดิกคินสัน

45
@zihotki: ผิด var a = 5; Console.WriteLine (@a); พิมพ์ 5
SLaks

168

หากคุณต้องการออกจากโปรแกรมของคุณโดยไม่เรียกใช้บล็อกหรือFinalizersใด ๆ ให้ใช้FailFast :

Environment.FailFast()

12
โปรดทราบว่าวิธีนี้ยังสร้างการถ่ายโอนข้อมูลหน่วยความจำและเขียนข้อความลงในบันทึกข้อผิดพลาดของ Windows
RickNZ

1
ควรสังเกตว่าจะไม่มีการยกเลิกกิจกรรมขั้นสุดท้ายหรือการยกเลิกการโหลดโดเมนแอปเมื่อมีการใช้วิธีการนี้ ...
AwkwardCoder

1
+1 สำหรับคำใบ้ แต่นี่ไม่ใช่ C # มันคือ BCL ของ. NET
Abel

System.Diagnostics.Process.GetCurrentProcess (). Kill () เร็วขึ้น
Tolgahan Albayrak

153

การคืนค่าประเภทที่ไม่ระบุชื่อจากวิธีการและการเข้าถึงสมาชิกโดยไม่สะท้อน

// Useful? probably not.
private void foo()
{
    var user = AnonCast(GetUserTuple(), new { Name = default(string), Badges = default(int) });
    Console.WriteLine("Name: {0} Badges: {1}", user.Name, user.Badges);
}

object GetUserTuple()
{
    return new { Name = "dp", Badges = 5 };
}    

// Using the magic of Type Inference...
static T AnonCast<T>(object obj, T t)
{
   return (T) obj;
}

42
ที่จริงไม่ได้รับอะไรเลย มันอันตรายจริงๆ เกิดอะไรขึ้นถ้า GetUserTuple ถูกปรับเปลี่ยนเพื่อส่งคืนหลายชนิด? การร่ายจะล้มเหลวในเวลาทำงาน หนึ่งในสิ่งที่ยอดเยี่ยมเกี่ยวกับ C # /. Net คือการตรวจสอบเวลารวบรวม มันจะดีกว่ามากถ้าเพียงแค่สร้างรูปแบบใหม่
Jason Jackson

9
@ Jason ฉันบอกว่ามันอาจจะไม่เป็นประโยชน์ แต่ก็น่าแปลกใจ (และฉันคิดว่าซ่อน)
ปฏิเสธฟิลลิปส์

31
ในขณะที่เท่สิ่งนี้ดูเหมือนจะเป็นตัวเลือกการออกแบบที่ค่อนข้างแย่ โดยทั่วไปคุณได้กำหนดประเภทที่ไม่ระบุชื่อในสองแห่ง ณ จุดนี้เพียงประกาศโครงสร้างที่แท้จริงและใช้งานได้โดยตรง
Paul Alexander

6
@ George: การประชุมดังกล่าวจะเรียกว่า ... struct?
R. Martinho Fernandes

2
เคล็ดลับนี้มีชื่อว่า 'นำแสดงโดยตัวอย่าง' และจะไม่ทำงานถ้าวิธีที่ส่งกลับชนิดไม่ระบุชื่ออยู่ในแอสเซมบลีอื่น
desco

146

ต่อไปนี้เป็นประโยชน์สำหรับนิพจน์ทั่วไปและเส้นทางไฟล์:

"c:\\program files\\oldway"
@"c:\program file\newway"

@ บอกคอมไพเลอร์เพื่อละเว้นอักขระเลี่ยงใด ๆ ในสตริง


27
นอกจากนี้ค่าคงที่ @ ยอมรับการขึ้นบรรทัดใหม่ภายใน สมบูรณ์แบบเมื่อกำหนดสคริปต์หลายบรรทัดให้กับสตริง
Tor Haugen

11
อย่าลืมที่จะหลีกเลี่ยงเครื่องหมายคำพูดเพียงแค่เพิ่มเป็นสองเท่าในคำอื่น ๆ [code] var candy = @ "ฉันชอบ" "สีแดง" "candy canes"; [/ code]
เดฟ

5
ฉันมักจะสร้างเส้นทางด้วย Path.Combine ฉันใช้ @ สำหรับ regex อย่างแน่นอน!
Dan McClain

6
@new เป็นตัวแปรแทนที่จะใช้คำหลัก: @this, @int, @return, @interface ... เป็นต้น :)
IAbstract

สิ่งนี้ไม่ได้มาใกล้ทุกที่: แต่สิ่งที่เป็นคุณสมบัติหรือลูกเล่นที่ซ่อนอยู่มากที่สุดของ C # ที่แม้แต่แฟน C #, ผู้ติดยา, ผู้เชี่ยวชาญแทบจะไม่รู้
publicgk

141

mixins โดยทั่วไปหากคุณต้องการเพิ่มคุณสมบัติให้กับหลาย ๆ คลาส แต่ไม่สามารถใช้หนึ่งคลาสพื้นฐานสำหรับทุกคลาสให้ใช้แต่ละคลาสเพื่อใช้อินเทอร์เฟซ (โดยไม่มีสมาชิก) จากนั้นเขียนวิธีการต่อเติมสำหรับส่วนต่อประสานเช่น

public static DeepCopy(this IPrototype p) { ... }

แน่นอนมีความชัดเจนบางอย่างเสียสละ แต่มันใช้งานได้!


4
ใช่ฉันคิดว่านี่เป็นพลังที่แท้จริงของวิธีการขยาย โดยทั่วไปจะอนุญาตให้มีการใช้งานวิธีการอินเทอร์เฟซ
John Bubriski

สิ่งนี้มีประโยชน์ถ้าคุณใช้ NHibernate (หรือ Castle ActiveRecord) และคุณต้องใช้อินเตอร์เฟสสำหรับคอลเลกชันของคุณ วิธีนี้คุณสามารถกำหนดพฤติกรรมให้กับอินเตอร์เฟสการรวบรวม
Ryan Lundy

นั่นเป็นวิธีการใช้งาน LINQ ทั้งหมดสำหรับบันทึก
WCWedin

นี่คือลิงค์ที่พูดถึงสิ่งที่ฉันอ้างถึงข้างต้นโดยใช้วิธีการขยายพร้อมส่วนต่อประสานการเก็บข้อมูลใน NHibernate หรือ Castle ActiveRecord: devlicio.us/blogs/billy_mccafferty/archive/2008/09/03/…
Ryan Lundy

7
ถ้าเพียงพวกเขาอนุญาตให้คุณสมบัติส่วนขยาย !!!! ฉันเกลียดที่จะต้องเขียนวิธีขยายที่ขอร้องให้เป็นสถานที่ให้อ่านอย่างเดียว ....
จอห์นกิบบ์

130

ไม่แน่ใจว่าทำไมทุกคนถึงต้องการใช้ Nullable <bool> :-)

จริงเท็จ, FileNotFound ?


87
หากคาดหวังว่าผู้ใช้จะตอบคำถามว่าใช่แล้วคำถามจะไม่เหมาะสมถ้าคำถามนั้นยังไม่ได้รับคำตอบ
Omar Kooheji

22
ชนิดที่มีค่าเป็นประโยชน์สำหรับการโต้ตอบกับฐานข้อมูลซึ่งคอลัมน์ของตารางมักจะเป็นโมฆะ
tuinstoel

11
ใช่ไม่ Maybee?
Dan Blair

21
เก็บค่าของกล่องกาเครื่องหมาย ThreeState
Shimmy Weitzhandler

8
เช่นเดียวกับใน SQL: ใช่ / ไม่ใช่ / ไม่รู้จัก
erikkallen

116

อันนี้ไม่ได้ "ซ่อน" มากนักเพราะมันผิด

ความสนใจจำนวนมากจ่ายให้กับอัลกอริทึม "แผนที่", "ลด" และ "ตัวกรอง" สิ่งที่คนส่วนใหญ่ไม่ทราบคือ. NET 3.5 ได้เพิ่มอัลกอริธึมทั้งสามเหล่านี้ แต่ให้ชื่อ SQL-ish มากโดยอิงจากข้อเท็จจริงที่ว่าพวกเขาเป็นส่วนหนึ่งของ LINQ

"map" => เลือก
แปลงข้อมูลจากแบบฟอร์มหนึ่งเป็นอีกแบบหนึ่ง

"ลด" => รวมผล
รวมค่าเป็นผลลัพธ์เดียว

"filter" => โดยที่
กรองข้อมูลตามเกณฑ์

ความสามารถในการใช้ LINQ ในการทำงานแบบอินไลน์กับคอลเลกชันที่ใช้ในการทำซ้ำและเงื่อนไขนั้นมีค่าอย่างไม่น่าเชื่อ มันคุ้มค่าที่จะเรียนรู้ว่าวิธีการขยาย LINQ ทั้งหมดสามารถช่วยทำให้โค้ดของคุณมีขนาดกะทัดรัดและสามารถบำรุงรักษาได้มากขึ้น


1
เลือกทำหน้าที่เหมือนฟังก์ชัน "ส่งคืน" ใน monads ดูstackoverflow.com/questions/9033/hidden-features-of-c#405088
Mark Cidade

1
การใช้ "select" จำเป็นเฉพาะเมื่อคุณใช้ไวยากรณ์ SQLish หากคุณใช้ไวยากรณ์วิธีการส่วนขยาย - someCollection.Where (item => item.Price> 5.99M) - ไม่จำเป็นต้องใช้คำสั่ง select
แบรดวิลสัน

7
@Brad นั่นคือ (ที่) คือการดำเนินการตัวกรอง ลองใช้การทำแผนที่โดยไม่ต้องเลือก ...
Eloff

2
LINQ เป็นเรื่องใหญ่ที่เกิดขึ้นกับ C # ในความคิดของฉัน: stackoverflow.com/questions/2398818//
Leniel Maccaferri

1
ลายเซ็นที่เล็กที่สุดของ Aggregate คือฟังก์ชัน "ลด" ลายเซ็นตรงกลางของ Aggregate เป็นฟังก์ชัน "fold" ที่ทรงพลังกว่า!
Brett Widmeier

115
Environment.NewLine

สำหรับการขึ้นบรรทัดใหม่อิสระของระบบ


10
สิ่งที่น่ารำคาญเกี่ยวกับอันนี้คือมันไม่ได้รวมอยู่ในกรอบขนาดกะทัดรัด
Stormenet

14
มันมีค่าที่ชี้ให้เห็นว่าสิ่งนี้มีความเฉพาะกับแพลตฟอร์มโฮสต์ของแอปพลิเคชัน - ดังนั้นหากคุณกำลังสร้างข้อมูลสำหรับระบบอื่นคุณควรใช้ \ n หรือ \ r \ n อย่างเหมาะสม
ตาข่าย

นี่เป็นส่วนหนึ่งของ BCL ของ. NET ไม่ใช่คุณลักษณะของ C # ต่อ se
Abel

111

หากคุณกำลังพยายามใช้วงเล็บปีกกาภายในรูปแบบ String จัดรูปแบบ ...

int foo = 3;
string bar = "blind mice";
String.Format("{{I am in brackets!}} {0} {1}", foo, bar);
//Outputs "{I am in brackets!} 3 blind mice"

19
@Kyralessa: ที่จริงแล้วใช่พวกเขาจัดฟัน แต่ "วงเล็บปีกกา" เป็นชื่ออื่นสำหรับพวกเขา [และ]เป็นวงเล็บเหลี่ยมและ<และ>เป็นวงเล็บเหลี่ยม ดูen.wikipedia.org/wiki/Bracket
icktoofay

4
คุณถูก. แต่เมื่อฉันแสดงความคิดเห็นมันไม่ได้พูดวงเล็บ "หยิก"
Ryan Lundy

2
ดีมากที่จะชี้ให้เห็น จำ String.Format แรกของฉันดูเหมือนว่า: String.Format ("{0} ฉันอยู่ในวงเล็บปีกกา {1} {2} {3}", "{", "}", 3, "หนูตาบอด"); เมื่อฉันพบว่าการหลบหนีสิ่งเหล่านี้ทำได้โดยใช้ {{และ}} ฉันมีความสุขมาก :)
Gertjan

Muahahahaa ... การเขียนโปรแกรม 3 ปีใน. Net และฉันไม่รู้จักอันนี้ : D
Arnis Lapsa

วงเล็บ "หยิก" ทำหน้าที่คล้ายกับการหลบหนีลำดับ?
Pratik

104
  1. ?? - ผู้ประกอบการรวมตัวกัน
  2. การใช้ ( คำสั่ง / คำสั่ง ) - คำหลักที่ยอดเยี่ยมที่สามารถใช้งานได้มากกว่าการโทรออก
  3. อ่านอย่างเดียว - ควรใช้มากกว่านี้
  4. netmodules - แย่มากไม่มีการสนับสนุนใน Visual Studio

6
การใช้สามารถใช้เพื่อตั้งชื่อแทนเนมสเปซแบบยาวให้เป็นสตริงที่สะดวกกว่าเช่น: ใช้ ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; มีอีกมากที่นี่: msdn.microsoft.com/en-us/library/sf0df423.aspx
Dave R.

2
มันไม่เหมือนกันจริงๆ เมื่อเรียกใช้ Dispose คุณสามารถใช้คำสั่ง use เมื่อใช้นามแฝงประเภทที่คุณกำลังใช้ directive
Øyvind Skaar

2
ในกรณีที่คุณต้องการให้ชื่อ # 1 (เช่นเดียวกับที่คุณทำกับผู้ประกอบการที่ประกอบไปด้วย), ?? เรียกว่าตัวดำเนินการรวมศูนย์ว่าง
J. Steen

4
@LucasAardvark: ดังที่ J Steen พูดถึงมันเรียกว่าตัวดำเนินการรวมศูนย์ว่าง ค้นหาสิ่งนั้น!
kokos

1
เพื่อค้นหา ผู้ให้บริการที่ google ลอง: google.com/search?q=c%23+%3F%3F+operator
backslash17

103

@Ed ฉันรู้สึกประหม่าเล็กน้อยเกี่ยวกับการโพสต์สิ่งนี้เนื่องจากมันเป็นมากกว่า nitpicking เล็กน้อย อย่างไรก็ตามฉันจะชี้ให้เห็นว่าในตัวอย่างโค้ดของคุณ:

MyClass c;
  if (obj is MyClass)
    c = obj as MyClass

หากคุณกำลังจะใช้ 'คือ' ทำไมต้องติดตามด้วยนักแสดงที่ปลอดภัยโดยใช้ 'เป็น' หากคุณตรวจสอบว่า obj นั้นเป็น MyClass จริง ๆ แล้วตัวละครที่ได้มาตรฐาน

c = (MyClass)obj

... จะไม่ล้มเหลว

ในทำนองเดียวกันคุณสามารถพูดได้ว่า:

MyClass c = obj as MyClass;
if(c != null)
{
   ...
}

ฉันไม่รู้พอเกี่ยวกับอวัยวะภายในของ. NET เพื่อให้แน่ใจ แต่สัญชาตญาณของฉันบอกฉันว่าสิ่งนี้จะลดการดำเนินการปลดเปลื้องสูงสุดสองประเภทลงไปสูงสุด เป็นไปได้ยากที่จะทำลายธนาคารประมวลผลด้วยวิธีใดวิธีหนึ่ง โดยส่วนตัวแล้วฉันคิดว่ารูปแบบหลังดูสะอาดกว่าด้วย


16
หากนักแสดงเป็นประเภทที่แน่นอน (นักแสดงที่ "A" เมื่อวัตถุคือ "A" ไม่ได้มาจากมัน) นักแสดงที่ตรงคือ ~ 3x เร็วกว่า "เป็น" เมื่อทำการหล่อแบบที่ได้รับ (ร่ายไปที่ "A" เมื่อวัตถุคือ "B" ซึ่งได้มาจาก "A") การร่ายแบบตรงจะช้ากว่า ~ 0.1 เท่าเมื่อเทียบกับ "as" "is" จากนั้น "ตาม" เป็นเพียงโง่
P Daddy

2
ไม่ แต่คุณสามารถเขียน "if ((c = obj เป็น MyClass)! = null)"
Dave Van den Eynde

10
isและasผู้ใช้จะไม่ปลดเปลื้อง ดังนั้นรหัสข้างต้นจะถามกับisโอเปอเรเตอร์ถ้า obj ได้รับมาจาก MyClass (หรือมีการกำหนดระบบโดยปริยาย) นอกจากนี้ยังล้มเหลวในis nullทั้งสองกรณีขอบเหล่านี้อาจมีความสำคัญต่อรหัสของคุณ ตัวอย่างเช่นคุณอาจต้องการเขียน: if( obj == null || obj is MyClass ) c = (MyClass)obj; แต่สิ่งนี้แตกต่างจาก: try { c = (MyClass)obj; } catch { }เนื่องจากผู้ใช้เดิมจะไม่ทำการแปลงใด ๆ ที่ผู้ใช้กำหนด แต่อย่างหลังจะ โดยไม่ต้องnullตรวจสอบอดีตจะยังไม่ได้ตั้งค่าcเมื่อเป็นobj null
Adam Luter

2
ใน IL นักแสดงจะไปที่ CASTCLASS แต่คำสั่ง as / ไปที่คำสั่ง ISINST
John Gibb

5
ฉันได้ทำการทดสอบนี้IEnumerable<int>เพื่อคัดเลือกList<int>และคัดเลือกobject( new object()) ถึงIEnumerable<int>เพื่อให้แน่ใจว่าไม่มีข้อผิดพลาด: นักแสดงโดยตรง: 5.43ns, is-> เป็นนักแสดง: 6.75ns, นักแสดง: 5.69ns จากนั้นทดสอบการร่ายที่ไม่ถูกต้อง: การโยนโดยตรง: 3125000ns, การโยน: 5.41ns บทสรุป: หยุดกังวลเกี่ยวกับปัจจัย 1% และเพียงให้แน่ใจว่าคุณใช้เป็น / เมื่อนักแสดงอาจไม่ถูกต้องทำให้เกิดข้อยกเว้น (เช่นถ้าจัดการ) จะช้ากว่าการคัดเลือกนักแสดงเรากำลังพูดถึงปัจจัย 578000 ช้ากว่า โปรดจำไว้ว่าส่วนสุดท้ายส่วนที่เหลือไม่สำคัญ (. Net FW 4.0, release build)
Aidiakapi

98

อาจไม่ใช่เทคนิคขั้นสูง แต่อย่างหนึ่งที่ฉันเห็นตลอดเวลาที่ทำให้ฉันบ้า:

if (x == 1)
{
   x = 2;
}
else
{
   x = 3;
}

สามารถย่อไปที่:

x = (x==1) ? 2 : 3;

10
ผู้ประกอบการที่ประกอบไปด้วยถูกแบนในกลุ่มของฉัน บางคนไม่ชอบ แต่ฉันก็ไม่เคยเข้าใจว่าทำไม
จัสตินอาร์

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

16
สามารถย่อเป็น x ++; ตกลงมันไม่มีจุดหมาย ^^
François

5
@Gillaillaume: เพื่อบัญชีสำหรับค่าทั้งหมดของ x: x = 2 + System.Math.Min (1, System.Math.Abs ​​(x-1));
mbeckish

38
ก็จริงที่เรียกว่า "ผู้ประกอบการที่มีเงื่อนไข" - มันเป็นประกอบ ternary เพราะมันใช้เวลาสามข้อโต้แย้ง en.wikipedia.org/wiki/Conditional_operator
Blorgbeard ออก
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.