เป็นการดีที่จะสืบทอดจากประเภททั่วไปหรือไม่?


35

มันจะดีกว่าที่จะใช้List<string>ในคำอธิบายประกอบประเภทหรือStringListที่ไหนStringList

class StringList : List<String> { /* no further code!*/ }

ฉันวิ่งเข้าไปในหลายของเหล่านี้ในประชด


หากคุณไม่สืบทอดจากประเภททั่วไปแล้วทำไมพวกเขาถึงอยู่ที่นั่น?
Mawg

7
@Mawg พวกเขาสามารถใช้ได้สำหรับการเริ่มต้นเท่านั้น
Theodoros Chatzigiannakis

3
นี่เป็นหนึ่งในสิ่งที่ฉันชอบน้อยที่สุดที่จะเห็นในโค้ด
Kik

4
yuck ไม่จริงจัง ความแตกต่างทางความหมายระหว่างStringListและList<string>คืออะไร ยังไม่มีคุณยัง (ทั่วไป "คุณ") จัดการเพื่อเพิ่มรายละเอียดอื่น ๆ ลงในฐานรหัสที่ไม่ซ้ำกันเฉพาะในโครงการของคุณและไม่มีความหมายกับคนอื่นจนกว่าจะได้ศึกษารหัสแล้ว เหตุใดจึงปิดบังชื่อของรายการสตริงเพื่อเรียกมันว่าเป็นรายการของสตริงเท่านั้น? ในทางกลับกันถ้าคุณต้องการBagOBagels : List<string>ฉันคิดว่ามันสมเหตุสมผลมากกว่า คุณสามารถย้ำให้มันเป็น IEnumerable ผู้บริโภคภายนอกไม่สนใจเกี่ยวกับการใช้งาน - คุณงามความดีทุกรอบ
Craig

1
XAML มีปัญหาที่คุณไม่สามารถใช้ยาชื่อสามัญได้และคุณจำเป็นต้องทำแบบนี้เพื่อเติมรายการ
Daniel Little

คำตอบ:


27

มีอีกเหตุผลที่คุณอาจต้องการรับช่วงจากประเภททั่วไป

ไมโครซอฟท์แนะนำให้หลีกเลี่ยงประเภททั่วไปทำรังในลายเซ็นวิธี

ดังนั้นจึงเป็นความคิดที่ดีที่จะสร้างชื่อโดเมนประเภทธุรกิจสำหรับข้อมูลทั่วไปของคุณ แทนที่จะมี a IEnumerable<IDictionary<string, MyClass>>ให้สร้างประเภทMyDictionary : IDictionary<string, MyClass>จากนั้นสมาชิกของคุณจะกลายเป็น an IEnumerable<MyDictionary>ซึ่งอ่านได้ง่ายกว่ามาก นอกจากนี้ยังช่วยให้คุณสามารถใช้ MyDictionary ในหลาย ๆ แห่งเพิ่มความชัดเจนให้กับโค้ดของคุณ

นี่อาจฟังดูไม่เป็นประโยชน์มากนัก แต่ในรหัสธุรกิจในโลกแห่งความจริงฉันเคยเห็นข้อมูลทั่วไปที่จะทำให้เส้นผมของคุณดูดี List<Tuple<string, Dictionary<int, List<Dictionary<string, List<double>>>>>สิ่งที่ต้องการ ความหมายของยาสามัญนั้นไม่ชัดเจน แต่ถ้ามันถูกสร้างขึ้นด้วยชุดของประเภทที่สร้างขึ้นอย่างชัดเจนเจตนาของนักพัฒนาดั้งเดิมน่าจะชัดเจนกว่ามาก ยิ่งไปกว่านั้นถ้าประเภทสามัญนั้นจำเป็นต้องเปลี่ยนด้วยเหตุผลบางอย่างการค้นหาและแทนที่อินสแตนซ์ทั้งหมดของประเภททั่วไปนั้นอาจเป็นความเจ็บปวดที่แท้จริงเมื่อเทียบกับการเปลี่ยนในคลาสที่ได้รับ

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

public class MyClass
{
    public ICollection<MyItems> MyItems { get; private set; }
    // plumbing code here
}

public class MyOtherClass
{
    public ICollection<MyItems> MyItemCache { get; private set; }
    // plumbing code here
}

public class MyConsumerClass
{
    public MyConsumerClass(ICollection<MyItems> myItems)
    {
        // use the collection
    }
}

ตอนนี้ทำอย่างไรเราจะได้รู้ว่าที่ICollection<MyItems>ที่จะผ่านเข้ามาสร้างสำหรับ MyConsumerClass? ถ้าเราสร้างคลาสที่ได้รับมาclass MyItems : ICollection<MyItems>และclass MyItemCache : ICollection<MyItems>MyConsumerClass สามารถระบุได้อย่างเฉพาะเจาะจงเกี่ยวกับว่ามีคอลเลกชันใดบ้างที่ต้องการ สิ่งนี้ทำงานได้ดีมากกับคอนเทนเนอร์ IoC ซึ่งสามารถแก้ไขคอลเลกชันทั้งสองได้อย่างง่ายดายมาก นอกจากนี้ยังช่วยให้โปรแกรมเมอร์มีความแม่นยำมากขึ้น - หากเหมาะสมกับMyConsumerClassการทำงานกับ ICollection ใด ๆ พวกเขาสามารถรับ Constructor ทั่วไปได้ อย่างไรก็ตามหากมันไม่เหมาะสมกับธุรกิจที่จะใช้หนึ่งในสองประเภทที่ได้รับผู้พัฒนาสามารถ จำกัด พารามิเตอร์ตัวสร้างเป็นประเภทเฉพาะ

โดยสรุปมันมักจะคุ้มค่าที่จะได้รับประเภทจากประเภททั่วไป - มันช่วยให้รหัสที่ชัดเจนมากขึ้นที่เหมาะสมและช่วยให้สามารถอ่านและบำรุงรักษา


12
นั่นเป็นคำแนะนำของ Microsoft ที่ไร้สาระอย่างแน่นอน
Thomas Eding

7
ฉันไม่คิดว่ามันไร้สาระสำหรับ API สาธารณะ ยาสามัญที่ซ้อนกันนั้นยากที่จะเข้าใจได้อย่างรวดเร็วและชื่อประเภทที่มีความหมายมากกว่านั้นมักจะช่วยให้สามารถอ่านได้
Stephen

4
ฉันไม่คิดว่ามันไร้สาระและมันก็โอเคสำหรับ API ส่วนตัว ... แต่สำหรับ API สาธารณะฉันไม่คิดว่ามันเป็นความคิดที่ดี แม้แต่ไมโครซอฟท์ก็แนะนำให้ยอมรับและส่งกลับประเภทพื้นฐานเมื่อคุณเขียน APIs เพื่อการบริโภคสาธารณะ
Paul d'Aoust

35

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

อย่างไรก็ตามทำไมบนโลกนี้คุณจะได้รับจากชั้นเรียนใด ๆและไม่เพิ่มอะไรอีกเลย?


17
ฉันเห็นด้วย. ฉันจะอ่าน "StringList" และคิดกับตัวเองโดยไม่ทำอะไรเลย " มันทำอะไรจริง ๆ "
Neil

1
ฉันเห็นด้วยเช่นกันในภาษาพฤษภาคมที่จะสืบทอดคุณใช้คำสำคัญ "ขยาย" นี่เป็นเครื่องเตือนความจำที่ดีว่าถ้าคุณจะรับช่วงเรียนคุณควรจะขยายมันด้วยการใช้งานเพิ่มเติม
Elliot Blackburn

14
-1, ไม่เข้าใจว่านี่เป็นเพียงวิธีเดียวในการสร้างสิ่งที่เป็นนามธรรมโดยการเลือกชื่อที่แตกต่าง - การสร้าง abstractions อาจเป็นเหตุผลที่ดีมากที่จะไม่เพิ่มอะไรลงในคลาสนี้
Doc Brown

1
พิจารณาคำตอบของฉันฉันไปด้วยเหตุผลบางอย่างที่คนอาจตัดสินใจทำ
NPSF3000

1
"ทำไมบนโลกนี้คุณจะได้รับจากชั้นเรียนใด ๆ และไม่เพิ่มอะไรอีกเลย" ฉันทำเพื่อควบคุมผู้ใช้ คุณสามารถสร้างการควบคุมผู้ใช้ทั่วไป แต่คุณไม่สามารถใช้มันในตัวออกแบบฟอร์ม windows ดังนั้นคุณต้องสืบทอดจากมันการระบุประเภทและใช้อันนั้น
George T

13

ฉันไม่รู้ C # ดีมาก แต่ฉันเชื่อว่านี่เป็นวิธีเดียวที่จะใช้ a typedefซึ่งโปรแกรมเมอร์ C ++ มักใช้ด้วยเหตุผลบางประการ:

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

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


7
เอ๊ะ ... มันไม่เหมือนกันเลย ใน C ++ คุณมีนามแฝงที่แท้จริง StringList เป็นList<string> - พวกเขาสามารถใช้แทนกันได้ นี้เป็นสิ่งสำคัญเมื่อทำงานกับ APIs อื่น ๆ (หรือเมื่อการเปิดเผย API ของคุณ) เนื่องจากคนอื่น ๆ List<string>ในการใช้งานทั่วโลก
Telastyn

2
ฉันรู้ว่าพวกเขาไม่ได้เหมือนกัน ใกล้เคียงที่สุดเท่าที่มีอยู่ มีข้อเสียอย่างแน่นอนสำหรับรุ่นที่อ่อนแอกว่า
Karl Bielefeldt

24
ไม่using StringList = List<string>;เทียบเท่ากับ C # ของ typedef การแบ่งคลาสย่อยเช่นนี้จะป้องกันการใช้ตัวสร้างใด ๆ ที่มีอาร์กิวเมนต์
Pete Kirkham

4
@PeteKirkham: การกำหนด StringList โดยusingจำกัด ไว้ที่ไฟล์ซอร์สโค้ดที่usingวางไว้ typedefจากมุมมองนี้มรดกอยู่ใกล้กับ และการสร้างคลาสย่อยไม่ได้ป้องกันสิ่งใดสิ่งหนึ่งจากการเพิ่มตัวสร้างทั้งหมดที่จำเป็น (แม้ว่ามันอาจจะน่าเบื่อ)
Doc Brown

2
@ Random832: ให้ฉันแสดงความแตกต่างนี้: ใน C ++, typedef สามารถใช้ในการกำหนดชื่อในที่เดียวเพื่อให้มันเป็น "แหล่งเดียวของความจริง" ใน C # usingไม่สามารถใช้เพื่อจุดประสงค์นี้ แต่สามารถรับมรดกได้ นี้แสดงให้เห็นว่าทำไมผมไม่เห็นด้วยที่จะแสดงความคิดเห็น upvoted พีทริ์ก - ฉันไม่ได้พิจารณาusingเป็นทางเลือกที่แท้จริงให้กับ c ++ typedef's
Doc Brown

9

ฉันสามารถคิดถึงเหตุผลเชิงปฏิบัติอย่างน้อยหนึ่งข้อ

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

กรณีหนึ่งคือเมื่อเพิ่มการตั้งค่าผ่านตัวแก้ไขการตั้งค่าใน Visual Studio ซึ่งดูเหมือนว่าจะมีเฉพาะประเภทที่ไม่ใช่ทั่วไปเท่านั้น หากคุณไปที่นั่นคุณจะสังเกตเห็นว่าSystem.Collectionsมีคลาสทั้งหมดแต่ไม่มีคอลเลกชันSystem.Collections.Genericปรากฏขึ้น

อีกกรณีคือเมื่อสร้างอินสแตนซ์ประเภทผ่าน XAML ใน WPF ไม่มีการสนับสนุนสำหรับการส่งผ่านอาร์กิวเมนต์ชนิดในไวยากรณ์ XML เมื่อใช้สกีมา pre-2009 สิ่งนี้ทำให้แย่ลงเนื่องจากข้อเท็จจริงที่ว่าสคีมาปี 2549 ดูเหมือนจะเป็นค่าเริ่มต้นสำหรับโครงการ WPF ใหม่


1
ในส่วนต่อประสานบริการเว็บของ WCF คุณสามารถใช้เทคนิคนี้เพื่อให้ชื่อประเภทคอลเลกชันที่ดูดีขึ้น (เช่น PersonCollection แทนที่จะเป็น ArrayOfPerson หรืออะไรก็ตาม)
Rico Suter

7

ฉันคิดว่าคุณต้องดูเป็นบางประวัติศาสตร์

  • มีการใช้ C # เป็นเวลานานกว่ารุ่นทั่วไป
  • ฉันคาดหวังว่าซอฟต์แวร์ที่กำหนดมี StringList ของตัวเอง ณ จุดหนึ่งในประวัติศาสตร์
  • สิ่งนี้อาจถูกนำไปใช้โดยการห่อ ArrayList
  • จากนั้นมีคน a ไปที่ refactoring เพื่อย้ายโค้ดไปข้างหน้า
  • แต่ไม่ต้องการแตะที่ 1001 ไฟล์ที่แตกต่างกันดังนั้นจบงาน

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


3
"C # มีการใช้งานนานกว่าที่เคยมีประเภททั่วไป" ไม่จริงๆ C # ที่ไม่มียาชื่อสามัญมีอยู่ประมาณ 4 ปี (มกราคม 2545 - พฤศจิกายน 2548) ในขณะที่ C # ที่มียาชื่อสามัญตอนนี้อายุ 9 ปี
svick

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

4

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

ถ้าเป็นไปได้ฉันจะหลีกเลี่ยง

แตกต่างจาก typedef คุณสร้างประเภทใหม่ ถ้าคุณใช้ StringList List<string>เป็นพารามิเตอร์ที่ป้อนให้กับวิธีการโทรของคุณไม่สามารถผ่าน

นอกจากนี้คุณจะต้องคัดลอก Constructor ทั้งหมดที่คุณต้องการใช้อย่างชัดเจนในตัวอย่าง StringList ที่คุณไม่สามารถพูดnew StringList(new[]{"a", "b", "c"})ได้แม้ว่าจะList<T>กำหนดตัวสร้างเช่นนั้น

แก้ไข:

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

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


3
คุณพูดว่า " คุณไม่สามารถอ้างอิงประเภททั่วไปใน XAML " แต่ฉันไม่แน่ใจว่าคุณหมายถึงอะไร ดูGenerics ใน XAML
pswg

1
มันมีความหมายเป็นตัวอย่าง ใช่มันเป็นไปได้กับ 2009 XAML Schema แต่ AFAIK ไม่ได้อยู่กับ Schema 2006 ซึ่งยังคงเป็นค่าเริ่มต้น VS
Lukas Rieger

1
ย่อหน้าที่สามของคุณเป็นเพียงครึ่งหนึ่งของความจริงคุณจริงสามารถช่วยให้นี้กับแปลงนัย;)
Knerd

1
@Knerd จริง แต่คุณ 'โดยปริยาย' สร้างวัตถุใหม่ นอกจากว่าคุณจะทำงานมากขึ้นสิ่งนี้จะสร้างสำเนาของข้อมูล อาจจะไม่ได้เป็นเรื่องที่มีรายการขนาดเล็ก แต่มีความสนุกสนานถ้ามีคนผ่านรายการที่มีไม่กี่พันองค์ประกอบ =)
Lukas Rieger

@LukasRieger คุณพูดถูก: PI แค่ต้องการชี้ให้เห็นว่า: P
Knerd

2

นี่คือตัวอย่างของการสืบทอดจากคลาสทั่วไปในคอมไพเลอร์ Roslyn ของ Microsoft และโดยไม่ต้องเปลี่ยนชื่อของคลาส (ฉันรู้สึกสับสนด้วยสิ่งนี้ฉันเลยลงเอยที่นี่เพื่อค้นหาว่ามันเป็นไปได้จริง ๆ หรือไม่)

ใน CodeAnalysis โครงการคุณสามารถค้นหาคำจำกัดความนี้:

/// <summary>
/// Common base class for C# and VB PE module builder.
/// </summary>
internal abstract class PEModuleBuilder<TCompilation, TSourceModuleSymbol, TAssemblySymbol, TTypeSymbol, TNamedTypeSymbol, TMethodSymbol, TSyntaxNode, TEmbeddedTypesManager, TModuleCompilationState> : CommonPEModuleBuilder, ITokenDeferral
    where TCompilation : Compilation
    where TSourceModuleSymbol : class, IModuleSymbol
    where TAssemblySymbol : class, IAssemblySymbol
    where TTypeSymbol : class
    where TNamedTypeSymbol : class, TTypeSymbol, Cci.INamespaceTypeDefinition
    where TMethodSymbol : class, Cci.IMethodDefinition
    where TSyntaxNode : SyntaxNode
    where TEmbeddedTypesManager : CommonEmbeddedTypesManager
    where TModuleCompilationState : ModuleCompilationState<TNamedTypeSymbol, TMethodSymbol>
{
  ...
}

จากนั้นในโครงการ CSharpCodeanalysis มีคำจำกัดความนี้:

internal abstract class PEModuleBuilder : PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, NoPia.EmbeddedTypesManager, ModuleCompilationState>
{
  ...
}

คลาส PEModuleBuilder ที่ไม่ใช่แบบทั่วไปนี้ถูกใช้อย่างกว้างขวางในโครงการ CSharpCodeanalysis และหลายคลาสในโครงการนั้นสืบทอดมาจากทางตรงหรือทางอ้อม

แล้วในโครงการ BasicCodeanalysis มีคำจำกัดความนี้:

Partial Friend MustInherit Class PEModuleBuilder
    Inherits PEModuleBuilder(Of VisualBasicCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, NoPia.EmbeddedTypesManager, ModuleCompilationState)

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


ใช่. และพวกเขายังสามารถใช้ในการปรับแต่งประโยคที่โดยตรงเมื่อมีการประกาศ
Sentinel

1

มีเหตุผลที่เป็นไปได้สามประการที่ทำไมบางคนพยายามทำสิ่งนั้นออกมาจากหัวของฉัน:

1) เพื่อทำให้การประกาศง่ายขึ้น:

แน่นอนStringListและListStringมีความยาวเท่ากัน แต่ลองจินตนาการว่าคุณกำลังทำงานกับสิ่งUserCollectionที่จริงDictionary<Tuple<string,Type>, IUserData<Dictionary,MySerializer>>หรือตัวอย่างทั่วไปขนาดใหญ่อื่น ๆ

2) เพื่อช่วยทอท.:

บางครั้งคุณต้องใช้การรวบรวมล่วงหน้าไม่เพียงรวบรวมเวลา - เช่นการพัฒนาสำหรับ iOS บางครั้งคอมไพเลอร์ AOT มีปัญหาในการหาประเภททั่วไปทั้งหมดล่วงหน้าและนี่อาจเป็นความพยายามที่จะให้คำแนะนำแก่มัน

3) เพื่อเพิ่มฟังก์ชั่นหรือลบการพึ่งพา:

บางทีพวกเขามีการทำงานที่เฉพาะเจาะจงว่าพวกเขาต้องการที่จะใช้สำหรับStringList(อาจจะซ่อนอยู่ในวิธีขยาย, ไม่ได้เพิ่มเลยหรือประวัติศาสตร์) ที่พวกเขาทั้งสองไม่สามารถเพิ่มList<string>ได้โดยไม่ต้องสืบทอดจากมันหรือว่าพวกเขาไม่ต้องการที่จะก่อให้เกิดมลพิษList<string>กับ .

อีกทางเลือกหนึ่งที่พวกเขาอาจต้องการที่จะเปลี่ยนการดำเนินการStringListลงติดตามเพื่อให้มีการใช้เพียงชั้นเป็นเครื่องหมายสำหรับตอนนี้ (โดยปกติคุณต้องการให้ / อินเตอร์เฟซใช้งานสำหรับการเช่นนี้IList)


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

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


หากคุณได้ดูซอร์สโค้ดมันจะปรากฏตัวเลือกที่ 3 คือเหตุผล - พวกเขาใช้เทคนิคนี้เพื่อช่วยเพิ่มฟังก์ชันการทำงาน / คอลเล็กชันที่เชี่ยวชาญ:

public class StringList : List<string> {
    public StringList() { }
    public StringList(params string[] args) {
      AddRange(args);
    }
    public override string ToString() {
      return ToString(" ");
    }
    public string ToString(string separator) {
      return Strings.JoinStrings(separator, this);
    }
    //Used in sorting suffixes and prefixes; longer strings must come first in sort order
    public static int LongerFirst(string x, string y) {
      try {//in case any of them is null
        if (x.Length > y.Length) return -1;
      } catch { }
      if (x == y) return 0;
      return 1; 
    }

1
บางครั้งการค้นหาเพื่อทำให้การประกาศง่ายขึ้น (หรือทำให้อะไรก็ตามง่ายขึ้น) อาจส่งผลให้เกิดความซับซ้อนเพิ่มขึ้นแทนที่จะลดความซับซ้อนลง ทุกคนที่รู้ภาษาที่ดีปานกลางรู้ว่าสิ่งที่List<T>เป็น แต่พวกเขามีการตรวจสอบStringListในบริบทที่จะเข้าใจจริงสิ่งที่มันเป็น ในความเป็นจริงมันเป็นList<string>ไปโดยใช้ชื่ออื่น ดูเหมือนจะไม่มีข้อได้เปรียบเชิงความหมายใด ๆ ในการทำสิ่งนี้ในกรณีง่าย ๆ คุณเพียงแค่แทนที่ประเภทที่รู้จักกันดีด้วยประเภทเดียวกันโดยใช้ชื่ออื่น
Craig

@ Craig ฉันยอมรับตามที่ระบุไว้โดยคำอธิบายของฉันของ usecase (ประกาศอีกต่อไป) และเหตุผลที่เป็นไปได้อื่น ๆ
NPSF3000

-1

ฉันจะบอกว่ามันไม่ใช่วิธีปฏิบัติที่ดี

List<string>สื่อสาร "รายการทั่วไปของสตริง" ใช้วิธีการขยายอย่างชัดเจน List<string>ความซับซ้อนน้อยกว่านั้นจะต้องเข้าใจ รายการเท่านั้นที่จำเป็น

StringListสื่อสาร "ต้องแยกชั้น" อาจ List<string>ใช้วิธีการขยาย (ตรวจสอบการใช้งานจริงประเภทนี้) จำเป็นต้องมีความซับซ้อนมากขึ้นในการทำความเข้าใจโค้ด รายการและความรู้การใช้งานคลาสที่ได้รับจำเป็นต้องมี


4
วิธีการขยายใช้อย่างไรก็ตาม
Theodoros Chatzigiannakis

2
แน่นอน. แต่คุณไม่ทราบว่าจนกว่าคุณตรวจสอบ StringList List<string>และเห็นมันเกิดขึ้นจาก
Ruudjah

@TheodorosChatzigiannakis ฉันสงสัยว่า Ruudjah สามารถอธิบายอย่างละเอียดเกี่ยวกับสิ่งที่เขาหมายถึงโดย "วิธีการขยายใช้ไม่ได้" วิธีการขยายเป็นไปได้กับชั้นเรียนใด ๆ แน่นอนว่า. NET Framework library มาพร้อมกับวิธีการขยายจำนวนมากที่เรียกว่า LINQ ซึ่งใช้กับคลาสคอลเลกชันทั่วไป แต่ไม่ได้หมายความว่าวิธีการขยายจะไม่ใช้กับคลาสอื่น ๆ ใช่หรือไม่ บางที Ruudjah กำลังสร้างประเด็นที่ไม่ชัดเจนในแวบแรก? ;-)
Craig

"วิธีการขยายใช้ไม่ได้" คุณอ่านสิ่งนี้อยู่ที่ไหน ฉันกำลังพูดว่า " อาจใช้วิธีการขยายได้
Ruudjah

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