ตัวอย่างการปฏิบัติที่สามารถใช้ Tuple ใน. Net 4.0?


97

ฉันเคยเห็น Tuple ที่เปิดตัวใน. Net 4 แต่ฉันนึกไม่ออกว่าจะใช้งานได้ที่ไหน เราสามารถสร้างคลาสหรือโครงสร้างแบบกำหนดเองได้เสมอ


13
บางทีนี่อาจเป็นจุดที่ดีที่จะทราบว่าหัวข้อนี้เก่ามาก ดูว่าเกิดอะไรขึ้นในC # 7 !
maf-soft

คำตอบ:


83

นั่นคือประเด็น - สะดวกกว่าที่จะไม่สร้างคลาสหรือโครงสร้างแบบกำหนดเองตลอดเวลา เป็นการปรับปรุงเช่นActionหรือFunc... คุณสามารถสร้างประเภทนี้ได้ด้วยตัวเอง แต่สะดวกที่มีอยู่ในกรอบ


5
อาจคุ้มค่าที่จะชี้ให้เห็นจากMSDN : "สมาชิกแบบคงที่สาธารณะประเภทนี้จะปลอดภัยต่อเธรดสมาชิกอินสแตนซ์ใด ๆ ไม่ได้รับการรับรองว่าเธรดจะปลอดภัย "
Matt Borja

บางทีนักออกแบบภาษาควรช่วยให้สร้างประเภทที่กำหนดเองได้ง่ายขึ้นในทันที? ดังนั้นเราจึงสามารถใช้ไวยากรณ์เดียวกันแทนที่จะแนะนำอีกแบบหนึ่ง?
Thomas Eyde

@ThomasEyde ซึ่งเป็นสิ่งที่พวกเขาทำในช่วง 15 ปีที่ผ่านมา นั่นเป็นวิธีการเพิ่มสมาชิกที่มีร่างกายของนิพจน์และตอนนี้ให้คุณค่ากับสิ่งที่เพิ่มขึ้น เรียนบันทึกแบบเฉียดหลังตัดในเดือนสิงหาคม (9 เดือนก่อนที่ความคิดเห็นนี้) สำหรับรุ่น C # 7 นี้และอาจจะออกมาใน C # 8. นอกจากนี้ทราบว่าค่า tuples มีความเท่าเทียมกันค่าที่เรียนธรรมดาเก่าไม่ได้ . การแนะนำทั้งหมดนี้ย้อนกลับไปในปี 2002 จะต้องใช้ความ
ระมัดระวัง

convenient not to make a custom classทำในสิ่งที่คุณหมายถึงโดย คุณหมายถึงการสร้างอินสแตนซ์คลาสที่กำหนดเองโดยใช้=new..()?
Alex

75

ด้วย tuples คุณสามารถใช้พจนานุกรมสองมิติ (หรือ n มิติสำหรับเรื่องนั้น) ได้อย่างง่ายดาย ตัวอย่างเช่นคุณสามารถใช้พจนานุกรมดังกล่าวเพื่อใช้การแมปการแลกเปลี่ยนสกุลเงิน:

var forex = new Dictionary<Tuple<string, string>, decimal>();
forex.Add(Tuple.Create("USD", "EUR"), 0.74850m); // 1 USD = 0.74850 EUR
forex.Add(Tuple.Create("USD", "GBP"), 0.64128m);
forex.Add(Tuple.Create("EUR", "USD"), 1.33635m);
forex.Add(Tuple.Create("EUR", "GBP"), 0.85677m);
forex.Add(Tuple.Create("GBP", "USD"), 1.55938m);
forex.Add(Tuple.Create("GBP", "EUR"), 1.16717m);
forex.Add(Tuple.Create("USD", "USD"), 1.00000m);
forex.Add(Tuple.Create("EUR", "EUR"), 1.00000m);
forex.Add(Tuple.Create("GBP", "GBP"), 1.00000m);

decimal result;
result = 35.0m * forex[Tuple.Create("USD", "EUR")]; // USD 35.00 = EUR 26.20
result = 35.0m * forex[Tuple.Create("EUR", "GBP")]; // EUR 35.00 = GBP 29.99
result = 35.0m * forex[Tuple.Create("GBP", "USD")]; // GBP 35.00 = USD 54.58

ฉันควรใช้ Enum สำหรับตัวย่อของประเทศ เป็นไปได้หรือไม่
Zack

1
แน่นอนว่าควรใช้งานได้โดยไม่มีปัญหาเนื่องจาก enums เป็นประเภทค่า
MarioVW

@MarioVW นอกจากนี้ยังสามารถทำได้โดยใช้อาร์เรย์หลายมิติ ทูเพิลสร้างความแตกต่างได้อย่างไร?
Alex

26

มีบทความที่ยอดเยี่ยมในนิตยสาร MSDN ที่พูดถึงข้อควรพิจารณาเกี่ยวกับการปวดท้องและการออกแบบที่เพิ่ม Tuple ลงใน BCL การเลือกระหว่างประเภทค่าและประเภทอ้างอิงเป็นสิ่งที่น่าสนใจอย่างยิ่ง

ตามที่บทความนี้มีความชัดเจนแรงผลักดันที่อยู่เบื้องหลัง Tuple คือกลุ่มต่างๆมากมายใน Microsoft ที่ใช้งานได้ทีม F # อยู่ข้างหน้า แม้ว่าจะไม่ได้กล่าวถึง แต่ฉันคิดว่าคีย์เวิร์ด "ไดนามิก" ใหม่ใน C # (และ VB.NET) ก็มีส่วนเกี่ยวข้องเช่นกันสิ่งที่เป็นสิ่งที่พบบ่อยมากในภาษาไดนามิก

เป็นอย่างอื่นโดยเฉพาะอย่างยิ่งไม่ได้ดีไปกว่าการสร้าง poco ของคุณเองอย่างน้อยคุณก็สามารถให้ชื่อที่ดีกว่าแก่สมาชิกได้


UPDATE: เนื่องจากการแก้ไขครั้งใหญ่ใน C # เวอร์ชัน 7 ตอนนี้ได้รับความรักทางไวยากรณ์มากขึ้น ประกาศเบื้องต้นในบล็อกโพสต์นี้


23

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

public static void Main(string[] args)
{
    int userId = 0;
    Tuple<string, string> userData = GetUserData(userId);
}

public static Tuple<string, string> GetUserData(int userId)
{
    return new Tuple<string, string>("Hello", "World");
}

10
อย่างไรก็ตามนี่เป็นตัวอย่างที่ดี แต่ไม่ได้แสดงให้เห็นถึงการใช้งาน Tuple
Amitabh

7
ทูเพิลเป็นแบบที่เหมาะสมเนื่องจากคุณกำลังส่งคืนค่าที่แตกต่างกัน แต่ tuple ส่องสว่างมากขึ้นเมื่อคุณกลับหลายค่าที่แตกต่างกันประเภท
Mark Rushakoff

21
อีกตัวอย่างที่ดีคือ int TryParse เนื่องจากคุณสามารถกำจัดพารามิเตอร์เอาต์พุตและใช้ Tuple แทน คุณสามารถมีTuple<bool, T> TryParse<T>(string input)และแทนที่จะต้องใช้พารามิเตอร์เอาต์พุตคุณจะได้รับทั้งสองค่ากลับมาในทูเพิล
Tejs

3
ในความเป็นจริงนั่นคือสิ่งที่เกิดขึ้นเมื่อคุณเรียกใช้เมธอด TryParse จาก F #
Joel Mueller

23

ฉันใช้ทูเพิลเพื่อแก้ปัญหา 11 ของ Project Euler :

class Grid
{
    public static int[,] Cells = { { 08, 02, 22, // whole grid omitted

    public static IEnumerable<Tuple<int, int, int, int>> ToList()
    {
        // code converts grid to enumeration every possible set of 4 per rules
        // code omitted
    }
}

ตอนนี้ฉันสามารถแก้ปัญหาทั้งหมดได้ด้วย:

class Program
{
    static void Main(string[] args)
    {
        int product = Grid.ToList().Max(t => t.Item1 * t.Item2 * t.Item3 * t.Item4);
        Console.WriteLine("Maximum product is {0}", product);
    }
}

ฉันสามารถใช้ประเภทที่กำหนดเองสำหรับสิ่งนี้ แต่มันจะดูเหมือนTupleทุกประการ


16

ไวยากรณ์ทูเปิลของ C # มีขนาดใหญ่อย่างน่าขันดังนั้นทูเปิลจึงเจ็บปวดที่จะประกาศ และไม่มีการจับคู่รูปแบบดังนั้นจึงต้องใช้ความเจ็บปวด

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

// sum and sum of squares at the same time
var x =
    Enumerable.Range(1, 100)
    .Aggregate((acc, x) => Tuple.Create(acc.Item1 + x, acc.Item2 + x * x));

แทนที่จะรวมคอลเล็กชันของค่าไว้ในผลลัพธ์เดียวให้ขยายผลลัพธ์เดียวให้เป็นคอลเล็กชันของค่า วิธีที่ง่ายที่สุดในการเขียนฟังก์ชันนี้คือ:

static IEnumerable<T> Unfold<T, State>(State seed, Func<State, Tuple<T, State>> f)
{
    Tuple<T, State> res;
    while ((res = f(seed)) != null)
    {
        yield return res.Item1;
        seed = res.Item2;
    }
}

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

คุณใช้มันดังนี้:

// return 0, 2, 3, 6, 8
var evens =
    Unfold(0, state => state < 10 ? Tuple.Create(state, state + 2) : null)
    .ToList();

// returns 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
var fibs =
    Unfold(Tuple.Create(0, 1), state => Tuple.Create(state.Item1, Tuple.Create(state.Item2, state.Item1 + state.Item2)))
    .Take(10).ToList();

evensค่อนข้างตรงไปตรงมา แต่fibsฉลาดกว่าเล็กน้อย stateแท้จริงแล้วมันคือทูเปิลที่มีเส้นใย (n-2) และเส้นใย (n-1) ตามลำดับ


4
+1 Tuple การสร้างเป็นชวเลขที่มีประโยชน์สำหรับnew Tuple<Guid,string,...>
AaronLS

@Juliet การใช้คำหลักของรัฐ
irfandar

7

ฉันไม่ชอบการใช้งานในทางที่ผิดเนื่องจากพวกเขาผลิตโค้ดที่ไม่ได้อธิบายตัวเอง แต่มันยอดเยี่ยมในการใช้คีย์ผสมแบบ on-the-fly เนื่องจากพวกเขาใช้ IStructuralEquatable และ IStructuralComparable (เพื่อใช้ทั้งในการค้นหาและสั่งซื้อ วัตถุประสงค์)

และรวมรหัสแฮชของรายการทั้งหมดไว้ภายใน ตัวอย่างเช่นนี่คือ GetHashCode ของ Tuple (นำมาจาก ILSpy):

    int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
    {
        return Tuple.CombineHashCodes(comparer.GetHashCode(this.m_Item1), comparer.GetHashCode(this.m_Item2), comparer.GetHashCode(this.m_Item3));
    }

7

Tuples เหมาะอย่างยิ่งสำหรับการดำเนินการ async IO หลายรายการพร้อมกันและคืนค่าทั้งหมดเข้าด้วยกัน นี่คือตัวอย่างของการทำด้วยและไม่มี Tuple Tuples สามารถทำให้โค้ดของคุณชัดเจนขึ้นได้จริง!

ไม่มี (รังที่น่ารังเกียจ!):

Task.Factory.StartNew(() => data.RetrieveServerNames())
    .ContinueWith(antecedent1 =>
        {
            if (!antecedent1.IsFaulted)
            {
                ServerNames = KeepExistingFilter(ServerNames, antecedent1.Result);
                Task.Factory.StartNew(() => data.RetrieveLogNames())
                    .ContinueWith(antecedent2 =>
                        {
                            if (antecedent2.IsFaulted)
                            {
                                LogNames = KeepExistingFilter(LogNames, antecedent2.Result);
                                Task.Factory.StartNew(() => data.RetrieveEntryTypes())
                                    .ContinueWith(antecedent3 =>
                                        {
                                            if (!antecedent3.IsFaulted)
                                            {
                                                EntryTypes = KeepExistingFilter(EntryTypes, antecedent3.Result);
                                            }
                                        });
                            }
                        });
            }
        });

ด้วย Tuple

Task.Factory.StartNew(() =>
    {
        List<string> serverNames = data.RetrieveServerNames();
        List<string> logNames = data.RetrieveLogNames();
        List<string> entryTypes = data.RetrieveEntryTypes();
        return Tuple.Create(serverNames, logNames, entryTypes);
    }).ContinueWith(antecedent =>
        {
            if (!antecedent.IsFaulted)
            {
                ServerNames = KeepExistingFilter(ServerNames, antecedent.Result.Item1);
                LogNames = KeepExistingFilter(LogNames, antecedent.Result.Item2);
                EntryTypes = KeepExistingFilter(EntryTypes, antecedent.Result.Item3);
            }
        });

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


5

Tuples ถูกใช้อย่างมากในภาษาที่ใช้งานได้ซึ่งสามารถทำสิ่งต่างๆได้มากขึ้นตอนนี้ F # เป็นภาษา. net 'ทางการ' ที่คุณอาจต้องการทำงานร่วมกับมันจาก C # และส่งต่อระหว่างโค้ดที่เขียนในสองภาษา


Tuples ยังสร้างขึ้นในประเภทสำหรับภาษาสคริปต์ยอดนิยมเช่น Python และ Ruby (ซึ่งมีการใช้งาน. Net สำหรับการทำงานร่วมกัน ... IronPython / Ruby)
MutantNinjaCodeMonkey

5

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

ตัวอย่างเช่นสมมติว่าคุณมีรายชื่อรถยนต์และเมืองที่ซื้อ:

Mercedes, Seattle
Mustang, Denver
Mercedes, Seattle
Porsche, Seattle
Tesla, Seattle
Mercedes, Seattle

คุณต้องการรวมจำนวนรถแต่ละคันต่อเมือง:

Mercedes, Seattle [3]
Mustang, Denver [1]
Porsche, Seattle [1]
Tesla, Seattle [1]

ในการดำเนินการนี้ให้คุณสร้างไฟล์Dictionary. คุณมีทางเลือกไม่กี่ทาง:

  1. สร้างไฟล์Dictionary<string, Dictionary<string, int>>.
  2. สร้างไฟล์Dictionary<CarAndCity, int>.
  3. สร้างไฟล์Dictionary<Tuple<string, string>, int>.

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

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

ตัวเลือกที่สามกระชับและสะอาด Tupleมันใช้ประโยชน์จาก


4

ตัวอย่างบางส่วนจากด้านบนของหัวของฉัน:

  • ตำแหน่ง X และ Y (และ Z ถ้าคุณต้องการ)
  • ความกว้างและความสูง
  • ทุกสิ่งที่วัดได้เมื่อเวลาผ่านไป

ตัวอย่างเช่นคุณไม่ต้องการรวม System.Drawing ไว้ในเว็บแอปพลิเคชันเพียงเพื่อใช้ Point / PointF และ Size / SizeF


2
Tupleมีประโยชน์พอ ๆ กับสถานการณ์ที่สำคัญPointหรือSomeVectorอาจเป็นประโยชน์เมื่อทำงานกราฟิก มันเน้นคุณค่าสองอย่างที่เชื่อมโยงกันมาก ฉันมักจะเห็นคุณสมบัติที่ชื่อ StartTime และ EndTime เมื่ออ่านโค้ด แต่จะดีกว่าเวลาวันที่และระยะเวลา Tuple บังคับให้คุณพิจารณาทั้งสองค่าทุกครั้งที่คุณดำเนินการในส่วนนี้ของตรรกะทางธุรกิจของคุณ หรือส่งคืน "เดี๋ยวก่อนข้อมูลมีการเปลี่ยนแปลง (บูล) นี่คือข้อมูล (ประเภทอื่น)" ในการประมวลผลหนักแทนที่จะใช้การเชื่อมโยงแบบเข้มข้น
Léon Pelletier

3

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

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


1

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

ทางเลือกง่ายๆอื่น ๆ คือการใช้พารามิเตอร์ 'out'

private string MyMethod(out object)

หรือทำพจนานุกรม

Dictionary<objectType1, objectType2>

อย่างไรก็ตามการใช้ Tuple จะช่วยประหยัดทั้งการสร้างอ็อบเจกต์ 'out' หรือต้องค้นหารายการในพจนานุกรมเป็นหลัก


1

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

งานคือการเขียนการตอบสนอง JSON จาก LINQ โดยไม่มีคลาสเพิ่มเติม:

 //I select some roles from my ORM my with subrequest and save results to Tuple list
 var rolesWithUsers = (from role in roles
                       select new Tuple<string, int, int>(
                         role.RoleName, 
                         role.RoleId, 
                         usersInRoles.Where(ur => ur.RoleId == role.RoleId).Count()
                      ));

 //Then I add some new element required element to this collection
 var tempResult = rolesWithUsers.ToList();
 tempResult.Add(new Tuple<string, int, int>(
                        "Empty", 
                         -1,
                         emptyRoleUsers.Count()
                      ));

 //And create a new anonimous class collection, based on my Tuple list
 tempResult.Select(item => new
            {
                GroupName = item.Item1,
                GroupId = item.Item2,
                Count = item.Item3
            });


 //And return it in JSON
 return new JavaScriptSerializer().Serialize(rolesWithUsers);

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


1

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

โค้ดตัวอย่างด้านล่าง

...
...
// calling code.
var userDetails = await GetUserDetails(userId);
Console.WriteLine("Username : {0}", userDetails.Item1);
Console.WriteLine("User Region Id : {0}", userDetails.Item2);
...
...

private async Tuple<string,int> GetUserDetails(int userId)
{
    return new Tuple<string,int>("Amogh",105);
    // Note that I can also use the existing helper method (Tuple.Create).
}

อ่านเพิ่มเติมเกี่ยวกับTuple ที่นี่ หวังว่านี่จะช่วยได้


ฉันคิดว่าคุณไม่ต้องการส่งคืนประเภทที่ไม่ระบุตัวตนหรือ Array (หรือเนื้อหาแบบไดนามิก)
ozzy432836

0

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

ตัวอย่าง:

var customerDetails = new Tuple<Customer, List<Address>>(mainCustomer, new List<Address> {mainCustomerAddress}).ToCustomerDetails();

วิธีการขยาย:

public static CustomerDetails ToCustomerDetails(this Tuple<Website.Customer, List<Website.Address>> customerAndAddress)
    {
        var mainAddress = customerAndAddress.Item2 != null ? customerAndAddress.Item2.SingleOrDefault(o => o.Type == "Main") : null;
        var customerDetails = new CustomerDetails
        {
            FirstName = customerAndAddress.Item1.Name,
            LastName = customerAndAddress.Item1.Surname,
            Title = customerAndAddress.Item1.Title,
            Dob = customerAndAddress.Item1.Dob,
            EmailAddress = customerAndAddress.Item1.Email,
            Gender = customerAndAddress.Item1.Gender,
            PrimaryPhoneNo = string.Format("{0}", customerAndAddress.Item1.Phone)
        };

        if (mainAddress != null)
        {
            customerDetails.AddressLine1 =
                !string.IsNullOrWhiteSpace(mainAddress.HouseName)
                    ? mainAddress.HouseName
                    : mainAddress.HouseNumber;
            customerDetails.AddressLine2 =
                !string.IsNullOrWhiteSpace(mainAddress.Street)
                    ? mainAddress.Street
                    : null;
            customerDetails.AddressLine3 =
                !string.IsNullOrWhiteSpace(mainAddress.Town) ? mainAddress.Town : null;
            customerDetails.AddressLine4 =
                !string.IsNullOrWhiteSpace(mainAddress.County)
                    ? mainAddress.County
                    : null;
            customerDetails.PostCode = mainAddress.PostCode;
        }
...
        return customerDetails;
    }

0

พารามิเตอร์ out จะดีมากเมื่อมีค่าเพียงไม่กี่ค่าที่ต้องส่งคืน แต่เมื่อคุณเริ่มพบค่า 4, 5, 6 หรือมากกว่าที่ต้องส่งคืนค่านั้นจะดูเทอะทะ อีกทางเลือกหนึ่งสำหรับการคืนค่าหลายค่าคือการสร้างและส่งคืนคลาส / โครงสร้างที่ผู้ใช้กำหนดเองหรือใช้ทูเพิลเพื่อจัดแพ็กเกจค่าทั้งหมดที่ต้องส่งคืนโดยวิธีการ

ตัวเลือกแรกโดยใช้คลาส / โครงสร้างเพื่อส่งคืนค่านั้นตรงไปตรงมา เพียงแค่สร้างประเภท (ในตัวอย่างนี้เป็นโครงสร้าง) ดังนี้:

public struct Dimensions
{
public int Height;
public int Width;
public int Depth;
}

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

var values = new Tuple<int, int, int, int, int, int, int, Tuple<int, int, int>> (
1, 2, 3, 4, 5, 6, 7, new Tuple<int, int, int> (8, 9, 10));

แน่นอนคุณสามารถเพิ่ม Tuples เพิ่มเติมต่อไปได้ในตอนท้ายของ Tuple ที่ฝังแต่ละตัวโดยสร้าง Tuple ขนาดใดก็ได้ที่คุณต้องการ


0

สำหรับการสร้างต้นแบบเท่านั้น - ทูเปิลไม่มีความหมาย สะดวกในการใช้ แต่เป็นทางลัดเท่านั้น! สำหรับต้นแบบ - ดี อย่าลืมลบรหัสนี้ในภายหลัง

เขียนง่ายอ่านยาก ไม่มีข้อได้เปรียบที่มองเห็นได้เหนือชั้นเรียนชั้นในชั้นเรียนที่ไม่ระบุตัวตนเป็นต้น


0

ฉันลอง 3 วิธีในการแก้ปัญหาเดียวกันใน C # 7 และฉันพบกรณีการใช้งานสำหรับทูเปิล

การทำงานกับข้อมูลแบบไดนามิกในโครงการเว็บบางครั้งอาจเป็นเรื่องยากลำบากเมื่อทำแผนที่เป็นต้น

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

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

using System;

namespace Playground
{
    class Program
    {
        static void Main(string[] args)
        {
            var tuple = GetTuple();
            Console.WriteLine(tuple.Item1);
            Console.WriteLine(tuple.Item2);
            Console.WriteLine(tuple.Item3);
            Console.WriteLine(tuple);

            Console.WriteLine("---");

            var dyn = GetDynamic();
            Console.WriteLine(dyn.First);
            Console.WriteLine(dyn.Last);
            Console.WriteLine(dyn.Age);
            Console.WriteLine(dyn);

            Console.WriteLine("---");

            var arr = GetArray();
            Console.WriteLine(arr[0]);
            Console.WriteLine(arr[1]);
            Console.WriteLine(arr[2]);
            Console.WriteLine(arr);

            Console.Read();

            (string, string, int) GetTuple()
            {
                return ("John", "Connor", 1);
            }

            dynamic GetDynamic()
            {
                return new { First = "John", Last = "Connor", Age = 1 };
            }

            dynamic[] GetArray()
            {
                return new dynamic[] { "John", "Connor", 1 };
            }
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.