Console.WriteLine () และต้องการอาร์กิวเมนต์มากเกินไป?


87

ฉันกำลังเรียกดูเอกสารและสังเกตเห็นว่าConsole.WriteLine()วิธีนี้มีการโอเวอร์โหลดหลายครั้ง โดยเฉพาะอย่างยิ่งความอยากรู้อยากเห็นและความสับสนบางส่วนของฉันเกี่ยวข้องกับสิ่งเหล่านี้:

public static void WriteLine(string format, params object[] arg);
public static void WriteLine(string format, object arg0);
public static void WriteLine(string format, object arg0, object arg1);
public static void WriteLine(string format, object arg0, object arg1, object arg2);
public static void WriteLine(string format, object arg0, object arg1, object arg2, object arg3);

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

คำตอบ:


102

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

delegate void E(string format, object o1);
E e = Console.WriteLine;

การparamsโอเวอร์โหลดจะไม่เป็นไปตามกรณีนี้จะใช้ได้เฉพาะเมื่อมีการโอเวอร์โหลดนี้เท่านั้น

public static void WriteLine(string format, object arg0);

นั่นเป็นกรณีที่ค่อนข้างลึกลับ สาเหตุที่สำคัญกว่ามีดังต่อไปนี้

  1. ไม่ใช่ทุกภาษา CLI ที่จำเป็นเพื่อรองรับparamsคำหลัก การมีโอเวอร์โหลดจะช่วยลดภาระของภาษาเหล่านั้นโดยไม่จำเป็นต้องสร้างอาร์เรย์ด้วยตนเองสำหรับการเรียก WriteLine` แบบธรรมดา
  2. ประสิทธิภาพ. การเรียกparamsโอเวอร์โหลดจะบังคับให้ผู้เรียกจัดสรรอาร์เรย์แม้ว่าคอมไพเลอร์จะทำโดยปริยายก็ตาม การจัดสรรมีราคาถูกใน. Net แต่ไม่ฟรี สิ่งเล็กน้อยเช่นนี้เพิ่มขึ้นอย่างรวดเร็วโดยเฉพาะอย่างยิ่งในวิธีการที่เรียกกันทั่วไปเช่นConsole.WriteLine. การมีโอเวอร์โหลดอื่น ๆ ทำให้กรณีทั่วไปหลีกเลี่ยงการจัดสรรนี้

1
ฉันเคยคิดเกี่ยวกับกรณีกลุ่มวิธีการในคำตอบของฉัน แต่ฉันค่อนข้างแน่ใจว่าการแปลงกลุ่มวิธีไม่ได้ถูกนำมาใช้จนกว่า C # 2.0 ในขณะที่ WriteLine โอเวอร์โหลดกลับไปเป็นอย่างน้อย 1.1
jaket

@jaket มีการเพิ่มไวยากรณ์ที่สะดวกใน C # 2.0 แต่จะมีผลเช่นเดียวกันหากคุณใช้ Explicit new E(Console.WriteLine)ใน C # 1
CodesInChaos

5
การจัดสรรอาร์เรย์เป็นที่สังเกตได้หรือไม่ว่า Console.WriteLine ช้าแค่ไหน?
Bryan Boettcher

3
@insta ไม่ใช่ความเร็ว แต่เป็นการสะสมการจัดสรรซึ่งเป็นปัญหา GC มีราคาถูกไม่ฟรีและในแอปที่ซับซ้อน GC มักเป็นปัจจัยด้านประสิทธิภาพที่เหนือกว่า การหยุดแหล่งที่มาทั่วไปของการจัดสรรที่ไม่จำเป็นเป็นสิ่งสำคัญสำหรับประสิทธิภาพ
JaredPar

38

การโอเวอร์โหลดมีไว้เพื่อความสะดวกของโปรแกรม C ++ / CLI ที่ไม่มีคีย์เวิร์ด params


1
นั่นเป็นคำตอบที่ดีสำหรับคำถามที่ดี IMHO เช่นกัน
Uwe Keim

1
อ่า ... นั่นเข้าท่าจริงๆ น่าละอายสำหรับฉัน C ++ เป็นภาษาแรกของฉัน :)
BK

3
พื้นฐานเริ่มจากภาษาแรกเพื่อนตอบฉลาด
dbw

4

ฉันคิดว่าพวกคุณทุกคนคงลืมไปว่า params ถูกนำมาใช้ใน C # 2.0 ดังนั้นการโอเวอร์โหลดยังมีอยู่จาก. NET 1.1 เมื่อไม่มีคีย์เวิร์ด params


jaket กล่าวถึงเรื่องนั้น
BK

อ่านความคิดเห็นของเขาเกี่ยวกับคำตอบของ JaredPar นั่นเป็นสาเหตุหนึ่งที่เขาไม่ใส่คำอธิบายพาราไว้ในคำตอบ
BK

@Noobacode จริงอยู่ที่เขาทำ แต่อนุมานได้ (ตามที่ฉันอ่าน) ฉันให้คะแนนโหวตเพิ่ม (เท่าที่มีค่า) ที่นี่เพราะเขาระบุไว้ในคฤหาสน์ที่ตรงกว่า
Frank V

1
จากคำหลัก params ลิงก์นี้มีอยู่ใน. net 1.1 ด้วย
Sriram Sakthivel

1

ฉันคิดว่าคำถามที่ถามมีคำตอบที่ดีและอธิบายได้อยู่แล้วโดยJaredParและjaketแต่สิ่งหนึ่งที่ฉันคิดว่าเกี่ยวข้องด้วยเช่นกัน

ฉันคิดว่าความสะดวกในการใช้งานและอิสระสำหรับผู้ใช้ในการใช้ฟังก์ชั่นใด ๆ ข้างต้นตามข้อกำหนดนั้นมีความต้องการที่สะดวกกว่ามากแทนที่จะกำหนดให้พวกเขาสร้างอาร์เรย์เมื่อพวกเขาไม่ต้องการจริงๆ

ฉันคิดว่าสมัยก่อนที่ฉันเริ่มเรียนรู้ C # ฉันแทบจะไม่ได้ใช้อาร์เรย์และการใช้อาร์เรย์เป็นงานที่ซับซ้อนสำหรับฉันการกำหนดและเริ่มต้นด้วยค่าที่เหมาะสมนั้นซับซ้อนมากและใช้เวลานานด้วย ...


3
แต่แนวคิดparamsคือคุณสามารถส่งอาร์เรย์หรือเขียนอาร์กิวเมนต์ทั้งหมดอย่างชัดเจน วิธีการเช่นvoid do(params object[])สามารถเรียกได้ว่าทั้งที่มีหรือdo(new object[] {"some", "stuff"} do("some", "stuff")ฉันไม่คิดว่าประเด็นของคุณจะใช้ได้กับที่นี่
Kroltan

2
@Kroltan แต่คุณบอกได้ไหมว่ามีผู้เริ่มต้นกี่คนที่รู้ความหมายจริงๆparamsและพวกเขารู้ว่าparamsมีอยู่หรือไม่คุณสามารถส่งผ่านตัวแปรโดยคั่นด้วยเครื่องหมายจุลภาค
dbw

1
@Kroltan ฉันก็ไม่รู้เหมือนกันว่าการใช้งานparamsอาจเป็นเช่นนี้มานานแล้วและในส่วนความช่วยเหลือที่แสดงใน Visual Studion หากฉันได้รับarray []เป็นอาร์กิวเมนต์ฉันจะคิดเหมือนกันในการจัดหาอาร์เรย์เป็นอาร์กิวเมนต์ ....
dbw

-3

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

โค้ดด้านล่างจะให้ข้อมูลเชิงลึกเล็กน้อยแก่คุณ

public class TipCalculator {
    private const double tipRate = 0.18;
    public static int Main(string[] args) {
        double billTotal;
        if (args.Length == 0) {
            Console.WriteLine("usage: TIPCALC total");
            return 1;
        }
        else {
            try {
                billTotal = Double.Parse(args[0]);
            }
            catch(FormatException) {
                Console.WriteLine("usage: TIPCALC total");
                return 1;
            }
            double tip = billTotal * tipRate;
            Console.WriteLine();
            Console.WriteLine("Bill total:\t{0,8:c}", billTotal);
            Console.WriteLine("Tip total/rate:\t{0,8:c} ({1:p1})", tip, tipRate);
            Console.WriteLine(("").PadRight(24, '-'));
            Console.WriteLine("Grand total:\t{0,8:c}", billTotal + tip);
            return 0;
        }
    }
}

โปรดดูลิงค์: http://msdn.microsoft.com/en-us/library/aa324774(v=vs.71).aspx สำหรับข้อมูลเพิ่มเติม


9
จะเพิ่มความสามารถในการใช้งานได้อย่างไร? วิธีแรกสามารถทำได้เหมือนกับอีกสี่วิธี คุณกำลังส่งเอกสารให้ฉันในขณะที่ฉันบอกว่ากำลังดูเอกสาร ฉันรู้ว่าวิธีนั้นใช้สำหรับอะไรและใช้อย่างไร (ฉันไม่ได้ใหม่กับ C # ไม่ว่าจะด้วยวิธีใดก็ตาม) แต่เหตุใดจึงต้องมีการโอเวอร์โหลดเพิ่มเติมนอกเหนือจากอันแรก
BK

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

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