การใช้. NET 4.0 Tuples ในรหัส C # ของฉันเป็นการตัดสินใจออกแบบที่ไม่ดีหรือไม่?


166

ด้วยการเพิ่มคลาสTupleใน. net 4 ฉันพยายามตัดสินใจว่าการใช้มันในการออกแบบของฉันนั้นเป็นตัวเลือกที่ไม่ดีหรือไม่ วิธีที่ฉันเห็นมันTupleสามารถเป็นทางลัดในการเขียนคลาสผลลัพธ์ (ฉันแน่ใจว่ามีการใช้อื่น ๆ ด้วย)

ดังนั้นนี่:

public class ResultType
{
    public string StringValue { get; set; }
    public int IntValue { get; set; }
}

public ResultType GetAClassedValue()
{
    //..Do Some Stuff
    ResultType result = new ResultType { StringValue = "A String", IntValue = 2 };
    return result;
}

เทียบเท่ากับสิ่งนี้:

public Tuple<string, int> GetATupledValue()
{
    //...Do Some stuff
    Tuple<string, int> result = new Tuple<string, int>("A String", 2);
    return result;
}

ดังนั้นการตั้งค่าความเป็นไปได้ที่ฉันพลาดจุด Tuples เป็นตัวอย่างของTuple ที่เป็นตัวเลือกการออกแบบที่ไม่ดีหรือไม่? สำหรับฉันดูเหมือนว่าจะมีความยุ่งเหยิงน้อยลง แต่ไม่ใช่เอกสารและทำความสะอาดตัวเอง ความหมายที่มีชนิดResultTypeนั้นชัดเจนมากในภายหลังในสิ่งที่แต่ละส่วนของชั้นเรียนหมายถึง แต่คุณมีรหัสพิเศษที่จะรักษา ด้วยการที่Tuple<string, int>คุณจะต้องค้นหาและคิดออกว่าแต่ละItemหมายถึง แต่คุณเขียนและรักษารหัสน้อย

ประสบการณ์ใด ๆ ที่คุณมีกับตัวเลือกนี้จะได้รับการชื่นชมอย่างมาก


16
@Boltbait: เพราะ tuple มาจากทฤษฎีเซตen.wikipedia.org/wiki/Tuple
Matthew Whited

16
@BoltBait: "tuple" เป็นชุดของค่าที่สั่งและไม่จำเป็นต้องทำอะไรกับแถวในฐานข้อมูล
FrustratedWithFormsDesigner

19
tuples ใน c # จะยิ่งดีกว่าถ้ามีบางสิ่งอันดับที่ดีเอาออกการกระทำ :)
จัสติน

4
@John Saunders คำถามของฉันเกี่ยวกับการตัดสินใจออกแบบใน c # โดยเฉพาะ ฉันไม่ได้ใช้ภาษา. net อื่น ๆ ดังนั้นฉันจึงไม่แน่ใจว่าสิ่งอันดับทูเปิลจะกระทบพวกเขาอย่างไร ดังนั้นฉันจึงทำเครื่องหมายว่า c # ดูเหมือนว่าสมเหตุสมผลสำหรับฉัน แต่การเปลี่ยนแปลงเป็น. net ก็ดีเช่นกันฉันเดา
Jason Webb

13
@ John Saunders: ฉันค่อนข้างแน่ใจว่าเขากำลังถามเกี่ยวกับการตัดสินใจออกแบบเกี่ยวกับการใช้หรือไม่ใช้ Tuples ในแอปพลิเคชันที่เขียนด้วยภาษา C # หมดจด ฉันไม่เชื่อว่าเขาถามเกี่ยวกับการตัดสินใจในการออกแบบที่ทำให้เกิดภาษา C #
Brett Widmeier

คำตอบ:


163

สิ่งอันดับที่ดีถ้าคุณควบคุมทั้งการสร้างและการใช้พวกเขา - คุณสามารถรักษาบริบทซึ่งเป็นสิ่งสำคัญในการทำความเข้าใจพวกเขา

อย่างไรก็ตามใน API สาธารณะจะมีประสิทธิภาพน้อยกว่า ผู้บริโภค (ไม่) Tuple<int, int>มีการคาดเดาหรือดูเอกสารโดยเฉพาะอย่างยิ่งสำหรับสิ่งที่ต้องการ

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

คำตอบนี้ยังมีข้อมูลบางอย่าง


19
ความแตกต่างระหว่างสาธารณะ / ส่วนตัวนั้นสำคัญมากขอบคุณที่นำมันขึ้นมา กลับ tuples ใน API สาธารณะของคุณเป็นความคิดที่ไม่ดีจริงๆ แต่ภายในสิ่งที่อาจจะมีคู่แน่น ( แต่ที่โอเค ) ก็ปรับ
Clinton Pierce

36
เชื่อมโยงอย่างแน่นหนาหรืออัดแน่น ;)
contactmatt

เอกสารที่เหมาะสมไม่สามารถใช้ประโยชน์ได้ที่นี่ใช่ไหม ตัวอย่างเช่น Scala's StringOps(โดยทั่วไปเป็นคลาสของ "วิธีการขยาย" สำหรับ Java's String) มีวิธีparition(Char => Boolean): (String, String)(ใช้ในการแสดงผลตอบแทน tuple ของ 2 สาย) เห็นได้ชัดว่าผลลัพธ์คืออะไร (เห็นได้ชัดว่าตัวละครหนึ่งจะเป็นตัวละครที่คำกริยานั้นเป็นจริงและอีกตัวที่มันเป็นเท็จ แต่ไม่ชัดเจนว่าเป็นแบบใด) มันเป็นเอกสารที่จะลบล้างสิ่งนี้ (และการจับคู่รูปแบบสามารถใช้เพื่อทำให้ชัดเจนในการใช้งานซึ่งเป็นสิ่งที่)
Kat

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

79

วิธีที่ฉันเห็นมัน Tuple เป็นทางลัดในการเขียนคลาสผลลัพธ์ (ฉันแน่ใจว่ามีการใช้อื่น ๆ ด้วย)

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

นี่คือตัวอย่างของการใช้งานที่สมเหตุสมผลสำหรับTuple<>:

var opponents = new Tuple<Player,Player>( playerBob, playerSam );

ในตัวอย่างข้างต้นเราต้องการแสดงคู่ของคู่ต่อสู้ tuple เป็นวิธีที่สะดวกในการจับคู่อินสแตนซ์เหล่านี้โดยไม่ต้องสร้างคลาสใหม่ นี่เป็นอีกตัวอย่าง:

var pokerHand = Tuple.Create( card1, card2, card3, card4, card5 );

มือโป๊กเกอร์สามารถคิดได้ว่าเป็นเพียงชุดไพ่ - และ tuple (อาจ) เป็นวิธีที่สมเหตุสมผลในการแสดงแนวคิดนั้น

ตั้งค่าความเป็นไปได้ที่ฉันพลาดจุด Tuples เป็นตัวอย่างที่ Tuple เป็นตัวเลือกการออกแบบที่ไม่ดีหรือไม่?

การส่งคืนTuple<>อินสแตนซ์ที่พิมพ์อย่างมากซึ่งเป็นส่วนหนึ่งของ API สาธารณะสำหรับประเภทสาธารณะไม่ค่อยเป็นความคิดที่ดี ในขณะที่คุณรับรู้สิ่งอันดับ tuples ต้องการฝ่ายต่างๆที่เกี่ยวข้อง (ผู้เขียนห้องสมุดผู้ใช้ห้องสมุด) เพื่อตกลงล่วงหน้าเกี่ยวกับวัตถุประสงค์และการตีความประเภท tuple ที่ใช้ มันท้าทายพอที่จะสร้าง API ที่ใช้งานง่ายและชัดเจนโดยใช้Tuple<>สาธารณะเท่านั้นบดบังเจตนาและพฤติกรรมของ API

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

My กฎของหัวแม่มือคือ: ถ้าคุณจะกลับมาได้จากอินเตอร์เฟซที่สาธารณะของคุณ - ทำให้มันเป็นชื่อประเภท

กฎง่ายๆอีกข้อของฉันสำหรับการใช้สิ่งอันดับคือ: อาร์กิวเมนต์เมธอดชื่อและตัวแปร localc ประเภทTuple<>อย่างชัดเจนที่สุด - ทำให้ชื่อเป็นตัวแทนของความหมายของความสัมพันธ์ระหว่างองค์ประกอบของสิ่งอันดับ นึกถึงvar opponents = ...ตัวอย่างของฉัน

นี่คือตัวอย่างของกรณีจริงที่ฉันเคยTuple<>หลีกเลี่ยงการประกาศชนิดข้อมูลอย่างเดียวเพื่อใช้ภายในแอสเซมบลีของตัวเองเท่านั้น สถานการณ์เกี่ยวข้องกับข้อเท็จจริงที่ว่าเมื่อใช้พจนานุกรมทั่วไปที่มีประเภทที่ไม่ระบุตัวตนมันเป็นการยากที่จะใช้TryGetValue()วิธีการค้นหารายการในพจนานุกรมเพราะวิธีการนั้นต้องการoutพารามิเตอร์ที่ไม่สามารถตั้งชื่อได้:

public static class DictionaryExt 
{
    // helper method that allows compiler to provide type inference
    // when attempting to locate optionally existent items in a dictionary
    public static Tuple<TValue,bool> Find<TKey,TValue>( 
        this IDictionary<TKey,TValue> dict, TKey keyToFind ) 
    {
        TValue foundValue = default(TValue);
        bool wasFound = dict.TryGetValue( keyToFind, out foundValue );
        return Tuple.Create( foundValue, wasFound );
    }
}

public class Program
{
    public static void Main()
    {
        var people = new[] { new { LastName = "Smith", FirstName = "Joe" },
                             new { LastName = "Sanders", FirstName = "Bob" } };

        var peopleDict = people.ToDictionary( d => d.LastName );

        // ??? foundItem <= what type would you put here?
        // peopleDict.TryGetValue( "Smith", out ??? );

        // so instead, we use our Find() extension:
        var result = peopleDict.Find( "Smith" );
        if( result.First )
        {
            Console.WriteLine( result.Second );
        }
    }
}

PSมีอีกวิธีหนึ่ง (เรียบง่าย) ในการแก้ไขปัญหาที่เกิดจากประเภทที่ไม่ระบุชื่อในพจนานุกรมและนั่นคือการใช้varคำหลักเพื่อให้คอมไพเลอร์ 'อนุมาน' ประเภทสำหรับคุณ นี่คือรุ่นของ:

var foundItem = peopleDict.FirstOrDefault().Value;
if( peopleDict.TryGetValue( "Smith", out foundItem ) )
{
   // use foundItem...
}

5
@stakx: ใช่ฉันเห็นด้วย แต่โปรดจำไว้ว่า - ตัวอย่างส่วนใหญ่มีจุดประสงค์เพื่อแสดงให้เห็นกรณีที่การใช้ a Tuple<> สามารถสร้างความเข้าใจได้ มีทางเลือกเสมอ ...
LBushkin

1
ฉันคิดว่าการแทนที่พารามิเตอร์ด้วย Tuple เช่นเดียวกับใน TryGetValue หรือ TryParse เป็นหนึ่งในไม่กี่กรณีที่อาจทำให้รู้สึกว่าการที่ API สาธารณะส่งคืน Tuple อันที่จริงแล้วภาษา. NET อย่างน้อยหนึ่งภาษาจะทำการเปลี่ยนแปลง API นี้ให้คุณโดยอัตโนมัติ
Joel Mueller

1
@stakx: สิ่งอันดับยังไม่เปลี่ยนรูปในขณะที่อาร์เรย์ไม่
Robert Paulson

2
ฉันเข้าใจว่า Tuples มีประโยชน์เฉพาะกับวัตถุผู้เล่นโป๊กเกอร์ที่ไม่เปลี่ยนรูป
Gennady Vanin ГеннадийВанин

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

18

สิ่งอันดับจะมีประโยชน์ ... แต่พวกเขาก็สามารถเจ็บปวดได้ในภายหลัง หากคุณมีวิธีที่คืนค่าTuple<int,string,string,int>คุณจะรู้ได้อย่างไรว่าค่าเหล่านั้นคืออะไรในภายหลัง พวกเขาหรือพวกเขาID, FirstName, LastName, AgeUnitNumber, Street, City, ZipCode


9

Tuples ค่อนข้างน่าสนใจนอกเหนือจาก CLR จากมุมมองของโปรแกรมเมอร์ C # หากคุณมีการรวบรวมรายการที่มีความยาวต่างกันคุณไม่จำเป็นต้องมีชื่อคงที่ที่ไม่ซ้ำกันในเวลารวบรวม

แต่ถ้าคุณมีคอลเลกชันที่มีความยาวคงที่นี่ก็หมายความว่าสถานที่ตั้งในคอลเลกชันแต่ละแห่งมีความหมายที่กำหนดไว้ล่วงหน้าเฉพาะ และมันก็เป็นเสมอดีกว่าที่จะให้พวกเขามีชื่อแบบคงที่ที่เหมาะสมในกรณีที่แทนที่จะต้องจำความสำคัญของItem1, Item2ฯลฯ

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

private var GetDesserts()
{
    return _icecreams.Select(
        i => new { icecream = i, topping = new Topping(i) }
    );
}

public void Eat()
{
    foreach (var dessert in GetDesserts())
    {
        dessert.icecream.AddTopping(dessert.topping);
        dessert.Eat();
    }
}

เป็นคุณสมบัติทั่วไปสิ่งที่ฉันต้องการจะเห็นคือ. net เพื่อกำหนดมาตรฐานสำหรับประเภทที่ไม่ระบุชื่อชนิดพิเศษสองสามอย่างเช่นเช่นstruct var SimpleStruct {int x, int y;}จะกำหนด struct ด้วยชื่อที่ขึ้นต้นด้วย guid ที่เกี่ยวข้องกับ structs ง่าย ๆ และ มีสิ่งที่ชอบ{System.Int16 x}{System.Int16 y}ผนวกเข้ามา; ชื่อใด ๆ ที่ขึ้นต้นด้วย GUID นั้นจะต้องแสดงถึงโครงสร้างที่ประกอบด้วยองค์ประกอบเหล่านั้นและเนื้อหาที่ระบุเฉพาะ หากคำจำกัดความหลายคำสำหรับชื่อเดียวกันอยู่ในขอบเขตและตรงกันทั้งหมดจะถือว่าเป็นประเภทเดียวกัน
supercat

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

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

คุณมีตัวอย่างที่เป็นรูปธรรมมากขึ้นว่าคุณจะใช้คลาสแบบไม่ระบุชื่อมากกว่าที่อื่นTupleหรือไม่ ฉันเพิ่งอ่านถึง 50 แห่งใน codebase ที่ฉันใช้ tuples และทั้งหมดเป็นค่าส่งคืน (โดยทั่วไปyield return) หรือเป็นองค์ประกอบของคอลเลกชันที่ใช้ที่อื่นดังนั้นจึงไม่มีคลาสที่ไม่ระบุชื่อ

2
@ JonofAllTrades - ความคิดเห็นอาจแตกต่างกันไป แต่ฉันพยายามออกแบบวิธีการสาธารณะราวกับว่าพวกเขาจะถูกใช้โดยคนอื่นแม้ว่าคน ๆ นั้นจะเป็นฉันดังนั้นฉันจึงให้บริการลูกค้าด้วยตัวเอง! คุณมักจะเรียกใช้ฟังก์ชันมากกว่าครั้งที่คุณเขียน :)
Daniel Earwicker

8

เช่นเดียวกับคำหลักvarมันมีจุดประสงค์เพื่อความสะดวก แต่มีการละเมิดอย่างง่ายดาย

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

// one possible use of tuple within a private context. would never
// return an opaque non-descript instance as a result, but useful
// when scope is known [ie private] and implementation intimacy is
// expected
public class WorkflowHost
{
    // a map of uri's to a workflow service definition 
    // and workflow service instance. By convention, first
    // element of tuple is definition, second element is
    // instance
    private Dictionary<Uri, Tuple<WorkflowService, WorkflowServiceHost>> _map = 
        new Dictionary<Uri, Tuple<WorkflowService, WorkflowServiceHost>> ();
}

2
ภาษาหลัก "RAD" (Java เป็นตัวอย่างที่ดีที่สุด) เลือกความปลอดภัยเสมอและหลีกเลี่ยงการถ่ายภาพตัวเองในสถานการณ์ประเภทเท้า ฉันดีใจที่ Microsoft ใช้โอกาสนี้กับ C # และให้ภาษาที่มีพลังดีแม้ว่ามันจะถูกนำไปใช้ในทางที่ผิด
Matt Greer

4
คำหลัก var ไม่สามารถละเมิด บางทีคุณอาจหมายถึงไดนามิก?
Chris Marisic

@ Chris Marisic เพียงชี้แจงฉันไม่ได้หมายถึงในสถานการณ์เดียวกัน - คุณถูกต้องอย่างแน่นอนvarไม่สามารถส่งคืนหรือมีอยู่นอกขอบเขตที่ประกาศไว้ แม้กระนั้นก็ยังสามารถใช้งานได้เกินความตั้งใจและเป็น "ใช้ผิดวิธี"
johnny g

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

4
var สามารถถูกทำร้ายได้ในแง่ที่ว่าหากมีการใช้งานมากเกินไปบางครั้งอาจทำให้เกิดปัญหาสำหรับผู้ที่อ่านรหัส โดยเฉพาะอย่างยิ่งถ้าคุณไม่ได้อยู่ใน Visual Studio และขาดความกระตือรือร้น
Matt Greer

5

การใช้คลาสResultTypeไลค์นั้นชัดเจนกว่า คุณสามารถให้ชื่อที่มีความหมายกับฟิลด์ในชั้นเรียน (ในขณะที่มีสิ่งอันดับพวกเขาจะถูกเรียกItem1และItem2) สิ่งนี้สำคัญยิ่งกว่าหากประเภทของทั้งสองฟิลด์เหมือนกัน: ชื่อจะแยกความแตกต่างระหว่างทั้งสองอย่างชัดเจน


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

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

5

วิธีการเกี่ยวกับการใช้ Tuples ในรูปแบบการตกแต่งเรียงลำดับไม่ได้ตกแต่ง? (Schwartzian Transform สำหรับคน Perl) นี่คือตัวอย่างที่คาดการณ์ไว้เพื่อให้แน่ใจ แต่ Tuples ดูเหมือนจะเป็นวิธีที่ดีในการจัดการสิ่งนี้:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] files = Directory.GetFiles("C:\\Windows")
                    .Select(x => new Tuple<string, string>(x, FirstLine(x)))
                    .OrderBy(x => x.Item2)
                    .Select(x => x.Item1).ToArray();
        }
        static string FirstLine(string path)
        {
            using (TextReader tr = new StreamReader(
                        File.Open(path, FileMode.Open)))
            {
                return tr.ReadLine();
            }
        }
    }
}

ตอนนี้ฉันสามารถใช้ Object [] ของสององค์ประกอบหรือในตัวอย่างเฉพาะนี้เป็นสตริง [] ของสององค์ประกอบ ประเด็นคือฉันสามารถใช้อะไรก็ได้เป็นองค์ประกอบที่สองใน Tuple ที่ใช้ภายในและอ่านง่าย


3
คุณสามารถใช้ Tuple.Create แทน Constructor มันสั้นกว่า
Kugel

ประเภทที่ไม่ระบุชื่อจะสามารถอ่านได้มากขึ้น จะใช้ชื่อตัวแปรจริงแทน 'x'
Dave Cousineau

มันจะตอนนี้ นั่นเป็นปัญหา SO คำตอบที่โพสต์เมื่อหลายปีก่อนไม่เคยทำความสะอาดหรืออัปเดตสำหรับเทคโนโลยีใหม่
Clinton Pierce

4

IMO เหล่านี้ "tuples" มีพื้นการเข้าถึงของประชาชนที่ไม่ระบุชื่อstructประเภทที่มีสมาชิกชื่อ

ที่เดียวที่ฉันจะใช้ tuple คือเมื่อคุณต้องการหยดข้อมูลบางอย่างเข้าด้วยกันอย่างรวดเร็วในขอบเขตที่ จำกัด มาก ความหมายของข้อมูลควรชัดเจนดังนั้นรหัสจึงไม่ยากที่จะอ่าน ดังนั้นการใช้ tuple ( int, int) สำหรับ (row, col) ดูเหมือนสมเหตุสมผล แต่ฉันรู้สึกกดดันที่จะหาข้อได้เปรียบเหนือstructสมาชิกที่มีชื่อ (ดังนั้นจึงไม่มีข้อผิดพลาดเกิดขึ้นและแถว / คอลัมน์ไม่ได้ถูกสับเปลี่ยนโดยไม่ตั้งใจ)

หากคุณกำลังส่งข้อมูลกลับไปยังผู้โทรหรือรับข้อมูลจากผู้โทรคุณควรใช้ a structกับสมาชิกที่มีชื่อ

ยกตัวอย่างง่ายๆ

struct Color{ float r,g,b,a ; }
public void setColor( Color color )
{
}

รุ่น tuple

public void setColor( Tuple<float,float,float,float> color )
{
  // why?
}

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

Tuple ทำให้ฉันขี้เกียจเพื่อหลีกเลี่ยงการสร้างstructสมาชิกที่มีชื่อจริง การใช้ tuple มากเกินไปซึ่งคุณรู้สึกว่าคุณ / หรือคนอื่นที่ต้องเผชิญกับรหัสของคุณจะต้องมีสมาชิกที่มีชื่อคือ A Bad Thing ™หากฉันเคยเห็น


3

อย่าตัดสินฉันไม่ใช่ผู้เชี่ยวชาญ แต่ด้วย Tuples ใหม่ใน C # 7.x ตอนนี้คุณสามารถส่งคืนสิ่งที่ชอบ:

return (string Name1, int Name2)

อย่างน้อยตอนนี้คุณสามารถตั้งชื่อได้และนักพัฒนาอาจเห็นข้อมูลบางอย่าง


2

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

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

ใช้ในการดูแลของหลักสูตร tuples สามารถนำไปสู่รหัสรัดกุมและอ่านง่ายขึ้น คุณสามารถดู C ++, STL และ Boost สำหรับตัวอย่างของการใช้ Tuples ในภาษาอื่น ๆ แต่ในที่สุดเราทุกคนจะต้องทดสอบเพื่อหาวิธีที่เหมาะสมที่สุดในสภาพแวดล้อม. NET


1

Tuples เป็นคุณสมบัติที่ไม่มีประโยชน์ใน. NET 4. ฉันคิดว่าโอกาสที่ยอดเยี่ยมพลาดไปกับ C # 4.0 ฉันอยากจะมีความรักที่จะมี tuples กับสมาชิกในการตั้งชื่อเพื่อให้คุณสามารถเข้าถึงด้านต่างๆของ tuple โดยใช้ชื่อแทนค่า 1 , Value2ฯลฯ ...

มันจะต้องมีการเปลี่ยนแปลงภาษา (ไวยากรณ์) แต่มันจะมีประโยชน์มาก


tuples เป็น "คุณสมบัติภาษา" ได้อย่างไร? เป็นคลาสที่ใช้ได้กับทุกภาษา. net ใช่ไหม
Jason Webb

11
ค่อนข้างไร้ประโยชน์กับ C # บางที แต่ System.Tuple ไม่ได้ถูกเพิ่มในเฟรมเวิร์กเนื่องจาก C # มันถูกเพิ่มเข้ามาเพื่อลดการทำงานร่วมกันระหว่าง F # และภาษาอื่น ๆ
Joel Mueller

@ Jason: ฉันไม่ได้บอกว่ามันเป็นคุณสมบัติภาษา (ฉันพิมพ์ผิด แต่ฉันแก้ไขก่อนที่คุณจะแสดงความคิดเห็นนี้)
Philippe Leybaert

2
@Jason - ภาษาที่มีการสนับสนุนโดยตรงสำหรับ tuples มีการสนับสนุนโดยนัยสำหรับ deconstructing tuples เป็นค่าส่วนประกอบ รหัสที่เขียนในภาษาเหล่านั้นมักจะไม่เคยเข้าถึงคุณสมบัติ Item1, Item2 let success, value = MethodThatReturnsATuple()
Joel Mueller

@Joel: คำถามนี้ถูกแท็กเป็น C # ดังนั้นจะเกี่ยวกับ C # ฉันยังคงคิดว่าพวกเขาสามารถเปลี่ยนให้เป็นคุณสมบัติชั้นหนึ่งในภาษา
Philippe Leybaert

1

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


0

ฉัน tuples สินค้าทั้งTupleใหม่และValueTupleในจำนวนของสถานการณ์ที่แตกต่างกันและมาถึงข้อสรุปต่อไปนี้: ไม่ได้ใช้

ทุกครั้งที่ฉันพบปัญหาต่อไปนี้:

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

ความคิดเห็นของฉันคือ tuples เป็นความเสียหายไม่ใช่คุณลักษณะของ C #

ฉันมีค่อนข้างคล้ายกัน แต่มีจำนวนมากที่รุนแรงน้อยกว่าการวิจารณ์ของและFunc<> Action<>สิ่งเหล่านั้นมีประโยชน์ในหลาย ๆ สถานการณ์โดยเฉพาะอย่างยิ่งสิ่งที่เรียบง่ายActionและFunc<type>หลากหลาย แต่นอกเหนือจากนั้นฉันพบว่าการสร้างประเภทของผู้ร่วมประชุมนั้นสง่างามอ่านง่ายบำรุงรักษาและให้คุณสมบัติเพิ่มเติมเช่นref/ outพารามิเตอร์


ฉันพูดถึงชื่อ tuples - ValueTuple- และฉันไม่ชอบพวกเขาเช่นกัน ครั้งแรกที่ตั้งชื่อไม่แข็งแรงก็มากขึ้นจากข้อเสนอแนะเรื่องง่ายมากที่จะเลอะเพราะมันสามารถกำหนดโดยปริยายอย่างใดอย่างหนึ่งTupleหรือValueTupleที่มีหมายเลขเดียวกันและประเภทของรายการ ประการที่สองการขาดการสืบทอดและความต้องการคัดลอกวางคำจำกัดความทั้งหมดจากที่หนึ่งไปอีกที่หนึ่งยังคงเป็นอันตราย
Mr. TA

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