วิธีการสามารถทำให้คงที่ แต่ควร?


366

Resharper ชอบที่จะชี้ให้เห็นถึงฟังก์ชั่นหลาย ๆ ต่อหน้า asp.net ที่สามารถทำให้คงที่ มันช่วยฉันได้ไหมถ้าฉันทำให้มันคงที่? ฉันควรทำให้พวกเขาคงที่และย้ายไปยังคลาสยูทิลิตี้?


20
Resharper ไม่ได้ตะโกนว่า "การทำงานร่วมกันต่ำ, การทำงานร่วมกันต่ำ" หรือไม่? ถึงเวลาที่จะดูว่าวิธีการที่เป็นจริงของชั้นเรียนที่
PK

คำตอบ:


245

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

กฎ CA1822 ใน FxCop หรือสถานะการวิเคราะห์รหัส:

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

คลาสยูทิลิตี้
คุณไม่ควรย้ายไปยังคลาสยูทิลิตี้เว้นแต่จะเหมาะสมในการออกแบบของคุณ หากวิธีการคงที่เกี่ยวข้องกับประเภทเฉพาะเช่นToRadians(double degrees)วิธีการที่เกี่ยวข้องกับชั้นเรียนที่เป็นตัวแทนมุมมันทำให้รู้สึกว่าวิธีการที่จะมีอยู่ในฐานะสมาชิกคงที่ของประเภทนั้น (หมายเหตุนี้เป็นตัวอย่างที่ซับซ้อนสำหรับวัตถุประสงค์ของการสาธิต)


2
> คอมไพเลอร์จะส่งไซต์โทรที่ไม่เสมือนไปยังสมาชิกเหล่านี้จริง ๆ แล้วนั่นคือ "คอมไพเลอร์อาจส่งเสียง ... " ฉันจำบางอย่างเกี่ยวกับคอมไพเลอร์ C # โดยใช้ callvirt แทนที่จะโทรเพื่อแก้ไขข้อผิดพลาดที่อาจเกิดขึ้น
Jonathan Allen

24
ฉันตัดและวางโดยตรงจาก FxCop 1.36 หาก FxCop ผิดยุติธรรมพอ
Jeff Yates

5
@ Maxim ไม่แน่ใจว่าฉันชื่นชมคำสั่ง "พล่าม"; วิธีหยาบคายสวยเข้าหาคนแปลกหน้า อย่างไรก็ตามจุดอ้างอิงนั้นถูกต้อง ฉันได้อัปเดตสิ่งต่าง ๆ เล็กน้อย (เมื่อ 9 ปีที่แล้วดังนั้นฉันไม่จำรากฐานของการอ้างสิทธิ์ดั้งเดิมของฉัน)
Jeff Yates

10
@Maxim จุดของคุณไม่ถูกต้อง ฉันขอยืนยันกับคุณว่าฉันไม่มีคะแนนที่ดีเมื่อ 9 ปีที่แล้ว ฉันขอขอบคุณสำหรับความคิดเห็นที่ชี้ให้เห็นข้อผิดพลาด (หรือการแก้ไขที่ถูกต้อง) แต่อย่าหยาบคายหรือวางความคาดหวังที่ไม่สมเหตุสมผลกับผู้อื่น อย่าเรียกบางอย่างว่า "พล่าม" มันแสดงถึงเจตนาที่จะหลอกลวงมากกว่าที่จะซื่อสัตย์ต่อความผิดพลาดหรือความไม่รู้ มันหยาบคาย ฉันอาสาเวลาของฉันเพื่อช่วยที่นี่และมันรู้สึกไร้จุดหมายจริง ๆ เมื่อได้รับการปฏิบัติด้วยความไม่เคารพ อย่าบอกฉันถึงสิ่งที่จะทำให้ขุ่นเคือง - นั่นคือทางเลือกของฉันไม่ใช่ของคุณ เรียนรู้วิธีทำให้จุดของคุณด้วยความเคารพและความซื่อสัตย์ ขอบคุณ.
Jeff Yates

2
@Maxim ในขณะที่ผู้ได้รับมอบหมายไม่ได้ถูกจัดเก็บไว้ข้างๆอินสแตนซ์แต่ละคลาสของคลาสไร้สัญชาติจะใช้หน่วยความจำบางส่วนบนฮีปซึ่งเป็นค่าใช้จ่ายที่ไร้ประโยชน์ โดยทั่วไปบริการ instantiating ไม่ใช่เส้นทางที่ร้อนแรงในแอปพลิเคชัน แต่ถ้าแอปพลิเคชันของคุณจบลงด้วยการสร้างวัตถุเหล่านี้จำนวนมากมันกำลังสร้างแรงกดดัน GC ที่สามารถหลีกเลี่ยงได้โดยการใช้วิธีการคงที่ การอ้างสิทธิ์ดั้งเดิมของ OP ว่าในสถานการณ์ที่รุนแรงวิธีการคงที่ให้ผลประโยชน์ด้านประสิทธิภาพมากกว่ากรณีไร้สัญชาตินั้นเหมาะสมและเหมาะสม
ซาด Saeeduddin

259

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

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


1
ฉันคิดว่าตัวเอนเตอร์ที่ดีควรมีตัวเลือกในการ จำกัด ข้อความให้เป็นวิธีการที่ไม่ใช่แบบเสมือนเนื่องจากมันจะเป็นเรื่องธรรมดามากสำหรับวิธีการเรียนแบบพื้นฐานที่จะไม่ทำอะไรเลย โดยทั่วไปแล้ววิธีการแทนที่จะทำอะไรบางอย่าง แต่ไม่เสมอไป บางครั้งมันมีประโยชน์ที่จะมีคลาสสำหรับบางสิ่งบางอย่างเช่น iEnumerable ที่ว่างเปล่าซึ่งมีวิธีการที่ไม่สนใจอินสแตนซ์ แต่โดยที่อินสแตนซ์นั้นจำเป็นต้องเลือกวิธีการใช้งานที่ถูกต้อง
supercat

2
"บางครั้งมีวิธีการที่มีเหตุผลในการกระทำบนอินสแตนซ์ แต่ยังไม่ได้ใช้สถานะของอินสแตนซ์ใด ๆ ตัวอย่างเช่น" ฉันชอบการใช้ "อินสแตนซ์" ในกรณีนี้
PaulBinder

56

การทำเครื่องหมายเมธอดstaticในคลาสทำให้เห็นได้ชัดว่าไม่ได้ใช้สมาชิกอินสแตนซ์ใด ๆ ซึ่งจะเป็นประโยชน์ในการรู้เมื่ออ่านผ่านโค้ด

คุณไม่จำเป็นต้องย้ายไปที่คลาสอื่นเว้นแต่ว่าจะมีการแชร์คลาสอื่นที่เชื่อมโยงกันอย่างใกล้ชิดและเป็นแนวคิดที่ชาญฉลาด


22

ฉันแน่ใจว่านี่ไม่ได้เกิดขึ้นในกรณีของคุณ แต่มี "กลิ่นเหม็น" ที่ฉันเคยเห็นในรหัสบางอย่างฉันต้องทนทุกข์ทรมานจากการบำรุงรักษาที่ใช้วิธีการคงที่จำนวนมาก

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

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

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


4
ปัญหาของคุณเกิดจากฟิลด์ / คุณสมบัติคงที่ไม่ใช่วิธีแบบคงที่
ซาด Saeeduddin

10

นี่คือการอ่านที่น่าสนใจ:

http://thecuttingledge.com/?p=57

ReSharper ไม่ได้แนะนำให้คุณทำให้วิธีการของคุณคงที่ คุณควรถามตัวเองว่าทำไมวิธีการนั้นถึงอยู่ในคลาสนั้นแทนที่จะพูดว่าหนึ่งในคลาสที่แสดงในลายเซ็นของมัน ...

แต่นี่คือสิ่งที่ resharper documentaion พูดว่า: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static


2
ฉันคิดว่าจุดนี้ด้อยค่า สิ่งที่เครื่องมือกำลังบอกคุณจริงๆก็คือวิธีการนี้ใช้กับสมาชิกของคลาสอื่นเท่านั้น หากเป็นวัตถุคำสั่ง (หรือ "ใช้เคส" หรือ "ผู้โต้ตอบ") ผู้รับผิดชอบในการจัดการกับวัตถุอื่นเป็นเรื่องปกติ อย่างไรก็ตามถ้ามันจัดการคลาสอื่น ๆ ที่ให้เสียงเหมือน Envy คุณลักษณะมาก
เกร็ก

9

เพียงเพิ่มคำตอบของ @Jason True สิ่งสำคัญคือต้องตระหนักว่าการใส่ 'คงที่' บนวิธีการไม่รับประกันว่าวิธีการนั้นจะ 'บริสุทธิ์' มันจะไร้สัญชาติโดยคำนึงถึงคลาสที่มีการประกาศ แต่อาจเข้าถึงวัตถุ 'สถิต' อื่น ๆ ที่มีสถานะ (การกำหนดค่าแอปพลิเคชัน ฯลฯ ) สิ่งนี้อาจไม่ได้เป็นสิ่งเลวร้ายเสมอไป แต่เป็นหนึ่งในเหตุผลที่ โดยส่วนตัวแล้วฉันมักจะชอบวิธีการแบบคงที่เมื่อฉันสามารถเป็นได้ว่าถ้าพวกเขาบริสุทธิ์คุณสามารถทดสอบและเหตุผลเกี่ยวกับพวกเขาในการแยกโดยไม่ต้องกังวลเกี่ยวกับสถานะโดยรอบ


6

คุณควรทำสิ่งที่สามารถอ่านได้และใช้งานง่ายที่สุดในสถานการณ์ที่กำหนด

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


6

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

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


5

ReSharper ไม่ได้ตรวจสอบตรรกะ มันจะตรวจสอบว่าวิธีการใช้สมาชิกอินสแตนซ์ หากวิธีนั้นเป็นแบบส่วนตัวและเรียกใช้โดยวิธีการอินสแตนซ์ (อาจเป็นเพียงหนึ่งเดียว) นี่เป็นสัญญาณเพื่อให้มันเป็นวิธีการแบบอินสแตนซ์


3

หากฟังก์ชั่นนั้นใช้ร่วมกันในหลาย ๆ หน้าคุณสามารถใส่มันลงในคลาสของเพจฐานแล้วให้เพจ asp.net ทั้งหมดที่ใช้ฟังก์ชันนั้นสืบทอดมาจากฟังก์ชันนั้น


3

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


Java ต้องการให้คุณสร้างอินสแตนซ์จากโรงงานเพื่อสร้างออบเจกต์คอนโซลก่อนเรียกใช้ con.Writeline ()
ScottMichaud

2

ช่วยควบคุมเนมสเปซมลพิษ


8
การสร้างวิธีการแบบคงที่ช่วยหลีกเลี่ยงมลภาวะ namespace ได้อย่างไร
lockstock

1
จากประสบการณ์โดยการจัดกลุ่มวิธีเป็นคลาสด้วยวิธีการคงที่คุณจะหลีกเลี่ยงประสบการณ์ที่จะต้องนำหน้า "คว้าถุง" ทั้งหมดของฟังก์ชั่นหลวมที่อาจขัดแย้งกับห้องสมุดอื่นหรือฟังก์ชั่นในตัว ด้วยวิธีการคงที่พวกเขากำลังตั้งชื่ออย่างมีประสิทธิภาพภายใต้ Classname เช่น Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi

0

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

using static className; 

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

ฉันไม่รู้ว่านี่เป็นการฝึกฝนที่ดีหรือไม่ ฉันมีอะไรมากมายที่ต้องเรียนรู้เกี่ยวกับ C # 4/5 และรหัสดั้งเดิมที่มากพอที่จะทำให้มั่นใจได้ว่าฉันเพิ่งจะปล่อยให้เคล็ดลับ Roselyn แนะนำฉัน

โจอี้


0

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

คำตอบสั้น ๆ ของฉัน: ใช่คุณสามารถแปลงเป็นวิธีคงที่หาก Resharper แนะนำ ไม่มีอันตรายใด ๆ ในการทำเช่นนั้น แต่ด้วยการทำให้เมธอดคงที่คุณกำลังปกป้องเมธอดอยู่ดังนั้นคุณไม่ต้องส่งสมาชิกอินสแตนซ์ใด ๆ ไปยังเมธอดนั้นโดยไม่จำเป็น ด้วยวิธีนี้คุณสามารถบรรลุหลักการ OOP " ลดการเข้าถึงชั้นเรียนและสมาชิกให้น้อยที่สุด"

เมื่อ ReSharper แนะนำว่าวิธีการอินสแตนซ์สามารถแปลงเป็นวิธีการแบบคงที่ได้จริง ๆ แล้วจะบอกคุณว่า "ทำไม .. วิธีนี้กำลังนั่งอยู่ในชั้นเรียนนี้เพราะมันไม่ได้ใช้งานจริง ๆ ดังนั้นมันจึงให้อาหารแก่คุณ จากนั้นก็เป็นคุณที่สามารถตระหนักถึงความจำเป็นในการย้ายวิธีการนั้นไปยังคลาสยูทิลิตี้คงที่หรือไม่ ตามหลักการของ SOLID ชั้นเรียนควรมีความรับผิดชอบหลักเพียงข้อเดียว ดังนั้นคุณสามารถทำความสะอาดชั้นเรียนของคุณได้ดีขึ้น บางครั้งคุณต้องการวิธีการช่วยเหลือบางอย่างแม้ในคลาสอินสแตนซ์ของคุณ หากเป็นเช่นนั้นคุณอาจเก็บไว้ในตัวช่วย #region

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