คำตอบอื่น ๆได้ให้คำอธิบายที่ดีว่าเหตุใดพารามิเตอร์ทางเลือกจึงไม่สามารถเป็นนิพจน์แบบไดนามิกได้ แต่หากต้องการนับใหม่พารามิเตอร์เริ่มต้นจะทำงานเหมือนค่าคงที่ของเวลาในการคอมไพล์ นั่นหมายความว่าคอมไพลเลอร์ต้องสามารถประเมินและหาคำตอบได้ มีบางคนที่ต้องการให้ C # เพิ่มการสนับสนุนสำหรับคอมไพลเลอร์ที่ประเมินนิพจน์แบบไดนามิกเมื่อพบการประกาศค่าคงที่คุณลักษณะประเภทนี้จะเกี่ยวข้องกับวิธีการทำเครื่องหมายว่า "บริสุทธิ์" แต่นั่นไม่ใช่ความจริงในตอนนี้และอาจจะไม่มีเลย
หนึ่งทางเลือกในการใช้พารามิเตอร์ C # XmlReaderSettings
เริ่มต้นสำหรับวิธีการดังกล่าวจะใช้รูปแบบสุดขั้ว ในรูปแบบนี้กำหนดคลาสด้วยตัวสร้างแบบไม่มีพารามิเตอร์และคุณสมบัติที่เขียนได้แบบสาธารณะ จากนั้นแทนที่ตัวเลือกทั้งหมดด้วยค่าเริ่มต้นในวิธีการของคุณด้วยออบเจ็กต์ประเภทนี้ แม้แต่ทำให้วัตถุนี้เป็นทางเลือกโดยระบุค่าเริ่มต้นnull
สำหรับวัตถุนั้น ตัวอย่างเช่น:
public class FooSettings
{
public TimeSpan Span { get; set; } = TimeSpan.FromSeconds(2);
// I imagine that if you had a heavyweight default
// thing you’d want to avoid instantiating it right away
// because the caller might override that parameter. So, be
// lazy! (Or just directly store a factory lambda with Func<IThing>).
Lazy<IThing> thing = new Lazy<IThing>(() => new FatThing());
public IThing Thing
{
get { return thing.Value; }
set { thing = new Lazy<IThing>(() => value); }
}
// Another cool thing about this pattern is that you can
// add additional optional parameters in the future without
// even breaking ABI.
//bool FutureThing { get; set; } = true;
// You can even run very complicated code to populate properties
// if you cannot use a property initialization expression.
//public FooSettings() { }
}
public class Bar
{
public void Foo(FooSettings settings = null)
{
// Allow the caller to use *all* the defaults easily.
settings = settings ?? new FooSettings();
Console.WriteLine(settings.Span);
}
}
ในการเรียกใช้ไวยากรณ์แปลก ๆ เพื่อสร้างอินสแตนซ์และกำหนดคุณสมบัติทั้งหมดในนิพจน์เดียว:
bar.Foo(); // 00:00:02
bar.Foo(new FooSettings { Span = TimeSpan.FromDays(1), }); // 1.00:00:00
bar.Foo(new FooSettings { Thing = new MyCustomThing(), }); // 00:00:02
ข้อเสีย
นี่เป็นวิธีการที่มีน้ำหนักมากในการแก้ปัญหานี้ หากคุณกำลังเขียนอินเทอร์เฟซภายในที่รวดเร็วและสกปรกและทำให้เป็นTimeSpan
โมฆะและจัดการกับค่าว่างเหมือนกับค่าเริ่มต้นที่คุณต้องการจะทำงานได้ดีให้ทำเช่นนั้นแทน
นอกจากนี้หากคุณมีพารามิเตอร์จำนวนมากหรือกำลังเรียกใช้เมธอดในวง จำกัด สิ่งนี้จะมีค่าใช้จ่ายในการสร้างอินสแตนซ์คลาส แน่นอนว่าหากเรียกวิธีดังกล่าวแบบวนซ้ำมันอาจจะเป็นธรรมชาติและง่ายมากที่จะนำอินสแตนซ์ของFooSettings
วัตถุกลับมาใช้ใหม่
ประโยชน์ที่ได้รับ
ดังที่ฉันได้กล่าวไว้ในความคิดเห็นในตัวอย่างฉันคิดว่ารูปแบบนี้เหมาะสำหรับ API สาธารณะ การเพิ่มคุณสมบัติใหม่ให้กับคลาสเป็นการเปลี่ยนแปลง ABI ที่ไม่ทำลายดังนั้นคุณสามารถเพิ่มพารามิเตอร์ทางเลือกใหม่โดยไม่ต้องเปลี่ยนลายเซ็นของวิธีการของคุณโดยใช้รูปแบบนี้ทำให้โค้ดที่คอมไพล์ล่าสุดมีตัวเลือกมากขึ้นในขณะที่ยังคงรองรับโค้ดที่คอมไพล์เก่าโดยไม่ต้องทำงานเพิ่มเติม .
นอกจากนี้เนื่องจากพารามิเตอร์เมธอดเริ่มต้นที่สร้างขึ้นใน C # จะถือว่าเป็นค่าคงที่ของเวลาคอมไพล์และอบลงใน callite พารามิเตอร์เริ่มต้นจะถูกใช้โดยรหัสเมื่อมีการคอมไพล์ใหม่เท่านั้น โดยการสร้างอินสแตนซ์ออบเจ็กต์การตั้งค่าผู้เรียกจะโหลดค่าเริ่มต้นแบบไดนามิกเมื่อเรียกใช้เมธอดของคุณ ซึ่งหมายความว่าคุณสามารถอัปเดตค่าเริ่มต้นได้เพียงแค่เปลี่ยนคลาสการตั้งค่าของคุณ ดังนั้นรูปแบบนี้ช่วยให้คุณสามารถเปลี่ยนค่าเริ่มต้นได้โดยไม่ต้องคอมไพล์ผู้โทรใหม่เพื่อดูค่าใหม่หากต้องการ
new TimeSpan(2000)
ไม่ได้หมายถึง 2,000 มิลลิวินาทีมันหมายถึง "เห็บ" 2,000 ตัวซึ่งเท่ากับ 0.2 มิลลิวินาทีหรือหนึ่ง 10,000 วินาทีของสองวินาที