เป็นการปฏิบัติที่ไม่ถูกต้องหรือไม่ที่จะใช้พารามิเตอร์วิธีการซ้ำ


12

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

void SanitizeName(string Name)
{
    Name = Name.ToUpper();

    //now do something here with name
}

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

ดังนั้นแทนที่จะกำหนดใหม่ให้กับข้อโต้แย้งตัวเองฉันมักจะสร้างสำเนาท้องถิ่นเช่น:

void SanitizeName(string Name)
{
    var SanitizedName = Name.ToUpper();

    //now do something here with name
}

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


1
ใช่มันเป็นการปฏิบัติที่ไม่ดี และไม่มันไม่เป็นอันตราย บรรทัดName = Name.ToUpper();ทำให้โค้ดยากต่อการติดตามในหัวของคุณเป็นค่าของNameการเปลี่ยนแปลง ตัวอย่างที่สองของคุณไม่เพียงพิสูจน์ได้ในอนาคตเท่านั้น แต่ยังง่ายกว่าที่จะให้เหตุผลว่าทำอะไรอยู่
David Arno

2
แต่เกี่ยวกับif (param == NULL) param = default_value;อะไร
aragaer

ฉันคิดว่ามันไม่ง่ายอย่างที่คิดใช่ / ไม่ใช่
MrSmith42

3
หาก"นักพัฒนาในอนาคตตัดสินใจที่จะมีค่าทั้งหมดที่ผ่านเข้ามาโดยอ้างอิง"ฉันอาจจะมีข้อโต้แย้งกับ dev นั้นนำมาใช้พารามิเตอร์ที่เกี่ยวข้องหรือไม่ ;-) สุจริตเมื่อหนึ่งตัดสินใจที่จะผ่านค่าby refที่ไม่ผ่านที่ ทางก่อนและดังนั้นการแปลงการเข้าถึงในท้องถิ่นเพื่อการเข้าถึงที่ไม่ใช่ท้องถิ่นด้วยเหตุผลบางอย่างเขามักจะตรวจสอบผลที่ตามมาอย่างรอบคอบ
Doc Brown

2
ฉันทำงานเป็นหลักในกระบวนทัศน์ที่เราไม่เคยกำหนดตัวแปรใด ๆ เคย มันตลกที่จะจินตนาการว่าใครบางคนกำลังดิ้นรนกับว่าพวกเขาควรจะกำหนดตัวแปรย่อยอีกเล็กน้อยหรือไม่
Karl Bielefeldt

คำตอบ:


10

ฉันคิดว่ามันขึ้นอยู่กับอนุสัญญาการเข้ารหัสของคุณในโครงการของคุณ

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

ในโครงการที่งานของฉันเราไม่แนะนำให้นำพารามิเตอร์มาใช้ซ้ำ แต่ถ้าคุณต้องการโทรเช่น.trim()หรือตั้งค่าเริ่มต้นในnullกรณีเราจะใช้พารามิเตอร์ส่วนใหญ่เนื่องจากการแนะนำตัวแปรใหม่ในกรณีเช่นนี้อ่านได้น้อยลง กว่าการใช้ซ้ำของพารามิเตอร์

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

ดังนั้นได้ร่วมกับทีมของคุณและกำหนดอนุสัญญาการเข้ารหัสที่ครอบคลุมเรื่องนี้


0

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


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

0

คำตอบนี้ขึ้นอยู่กับ 100% ว่าใครจะอ่านรหัสของคุณ รูปแบบใดที่พวกเขาพบว่ามีประโยชน์มากที่สุด

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

แบบจำลองจิตเปลี่ยนไป ในสภาพแวดล้อมการพัฒนาเฉพาะของคุณอาจเป็นที่ต้องการที่จะnameเป็น "การแสดงชื่อที่ดีที่สุด ณ เวลานี้" อาจเป็นที่พึงปรารถนาที่จะเชื่อมโยงตัวแปรที่คุณกำลังทำกับข้อโต้แย้งของพวกเขาอย่างชัดเจนยิ่งขึ้นแม้ว่าคุณจะทำการปรับเปลี่ยนค่าของพวกเขาไปพร้อมกัน อาจมีข้อได้เปรียบรันไทม์มากมายในการใช้ตัวแปรบางตัวซ้ำ ๆ แทนที่จะสร้างวัตถุขนาดใหญ่ขึ้น ท้ายที่สุดเมื่อคุณทำงานกับสาย 4GB มันเป็นการดีที่จะลดจำนวนสำเนาพิเศษที่คุณต้องทำ!


-1

ฉันมีปัญหาที่แตกต่างอย่างสิ้นเชิงกับตัวอย่างรหัสของคุณ:

SanitizeNameชื่อวิธีของคุณคือ ในกรณีนี้ผมคาดว่ามันจะsanitize ชื่อ ; เพราะนั่นคือสิ่งที่คุณบอกให้ผู้อ่านฟังก์ชั่นของคุณ

เพียงสิ่งที่คุณทำงานควรทำคือการฆ่าเชื้อที่กำหนดชื่อ โดยไม่ต้องอ่านรหัสของคุณฉันคาดหวังสิ่งต่อไปนี้:

string SanitizeName(string Name)
{
    //somehow sanitize the name
    return Result;
}

แต่คุณบอกเป็นนัยว่าวิธีการของคุณทำมากกว่าแค่ sanitizng นั่นเป็นกลิ่นรหัสและควรหลีกเลี่ยง

คำถามของคุณไม่เกี่ยวกับ: เป็นวิธีปฏิบัติที่ไม่ถูกต้องหรือไม่ที่จะนำพารามิเตอร์ของวิธีการมาใช้ซ้ำ มันเป็นมากกว่า: มีผลข้างเคียงและพฤติกรรมที่ไม่ได้ตรวจพบการปฏิบัติที่ไม่ดี?

คำตอบนั้นชัดเจน: ใช่!

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

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

ปัญหาคือน้อยนำมาใช้ใหม่กว่าsideeffects เพื่อป้องกันไม่ให้sideeffectsไม่ได้นำมาใช้ตัวแปร หากคุณไม่มีผลข้างเคียงจะไม่มีปัญหา


4
-1 สิ่งนี้ไม่ตอบคำถามเดิม รหัสที่ให้นั้นเป็นเพียงตัวอย่างรหัสสำหรับแสดงคำถามในมือ กรุณาตอบคำถามแทน "โจมตี" / ตรวจสอบรหัสตัวอย่างที่ให้ไว้
Niklas H

1
@NiklasH คำถามนี้ตอบได้อย่างสมบูรณ์แบบ: หากคุณจัดการพารามิเตอร์ภายในฟังก์ชั่นและตามที่คุณพูดถึงคุณทำงานกับการอ้างอิงโดยไม่ได้ตั้งใจแทนการคัดลอกสิ่งนี้จะทำให้เกิดผลข้างเคียง (เช่นที่ฉันพูด) เพื่อป้องกันไม่ให้สิ่งนั้นบ่งชี้ว่าคุณกำลังจะเปลี่ยนตัวแปรโดยเลือกชื่อเมธอดอย่างรอบคอบ (คิดว่ารูบี้ '!') และ / หรือเลือกประเภทส่งคืน หากคุณไม่เปลี่ยนตัวแปรให้ทำงานกับสำเนาเท่านั้น
โทมัสขยะ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.