Contoh praktis di mana Tuple dapat digunakan di .Net 4.0?

97

Saya telah melihat Tuple diperkenalkan di .Net 4 tetapi saya tidak dapat membayangkan di mana ia dapat digunakan. Kami selalu dapat membuat kelas atau Struct Kustom.

Amitabh
sumber
13
Mungkin ini tempat yang baik untuk mencatat bahwa topik ini sudah sangat tua. Lihat apa yang terjadi di C # 7 !
maf-soft

Jawaban:

83

Itulah intinya - lebih mudah untuk tidak membuat kelas atau struct kustom setiap saat. Ini adalah peningkatan seperti Actionatau Func... Anda dapat membuat tipe ini sendiri, tetapi nyaman bahwa mereka ada dalam kerangka kerja.

tanascius.dll
sumber
5
Mungkin perlu ditunjukkan dari MSDN : "Semua anggota statis publik jenis ini aman untuk thread. Semua anggota instance tidak dijamin aman untuk thread. "
Matt Borja
Nah, mungkin desainer bahasa seharusnya membuatnya lebih mudah untuk membuat jenis kustom dengan cepat, lalu? Jadi kita bisa tetap menggunakan sintaks yang sama alih-alih memperkenalkan yang lain?
Thomas Eyde
@ThomasEyde itulah yang telah mereka lakukan selama 15 tahun terakhir. Begitulah ekspresi anggota bertubuh ditambahkan, dan sekarang nilai tupel. Kelas rekor gaya nyaris kembali dipotong pada bulan Agustus (9 bulan sebelum komentar ini) untuk versi C # 7, dan mungkin keluar di C # 8. Juga mencatat bahwa nilai tupel menawarkan nilai kesetaraan di mana kelas plain-tua tidak . Memperkenalkan semua ini pada tahun 2002 membutuhkan
pengetahuan sebelumnya
apa yang Anda maksud dengan convenient not to make a custom class. Apakah yang Anda maksud membuat instance kelas kustom menggunakan =new..()?
Alex
75

Dengan tupel, Anda dapat dengan mudah mengimplementasikan kamus dua dimensi (atau n-dimensi dalam hal ini). Misalnya, Anda dapat menggunakan kamus semacam itu untuk mengimplementasikan pemetaan pertukaran mata uang:

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
MarioVW
sumber
Saya lebih suka menggunakan Enum untuk singkatan negara. Apakah itu mungkin?
Zack
1
Tentu, itu harus bekerja tanpa masalah karena enum adalah tipe nilai.
MarioVW
@MarioVW Itu juga bisa dilakukan dengan menggunakan array multi-dimensi. Bagaimana tuple membuat perbedaan?
Alex
26

Ada artikel bagus di majalah MSDN yang berbicara tentang sakit perut dan pertimbangan desain yang digunakan untuk menambahkan Tuple ke BCL. Memilih antara tipe nilai dan tipe referensi sangatlah menarik.

Seperti yang dijelaskan dalam artikel tersebut, kekuatan pendorong di belakang Tuple adalah begitu banyak kelompok di dalam Microsoft yang memanfaatkannya, tim F # di depan. Meskipun tidak disebutkan, menurut saya kata kunci "dinamis" baru di C # (dan VB.NET) ada hubungannya dengan itu juga, tupel sangat umum dalam bahasa dinamis.

Hal ini tidak terlalu unggul dari membuat poco Anda sendiri, setidaknya Anda dapat memberi nama yang lebih baik kepada anggota.


UPDATE: karena revisi besar dalam C # versi 7, sekarang mendapatkan lebih banyak cinta sintaks. Pengumuman awal di posting blog ini .

Hans Passant
sumber
23

Berikut adalah contoh kecil - misalnya Anda memiliki metode yang perlu mencari nama pengguna dan alamat email pengguna, dengan memberikan ID pengguna. Anda selalu dapat membuat kelas khusus yang berisi data tersebut, atau menggunakan parameter ref / out untuk data tersebut, atau Anda dapat mengembalikan Tuple dan memiliki tanda tangan metode yang bagus tanpa harus membuat POCO baru.

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");
}
Tejs
sumber
10
Ini adalah contoh yang bagus, namun tidak membenarkan penggunaan Tuple.
Amitabh
7
Sebuah tupel cocok di sini karena Anda mengembalikan nilai yang berbeda; tetapi tupel lebih bersinar saat Anda mengembalikan beberapa nilai dari tipe berbeda .
Mark Rushakoff
21
Contoh bagus lainnya adalah int.TryParse, karena Anda dapat menghilangkan parameter keluaran dan sebagai gantinya menggunakan Tuple. Jadi Anda bisa memiliki Tuple<bool, T> TryParse<T>(string input)dan alih-alih harus menggunakan parameter keluaran, Anda mendapatkan kedua nilai kembali dalam tupel.
Tejs
3
sebenarnya, itulah yang terjadi ketika Anda memanggil metode TryParse dari F #.
Joel Mueller
23

Saya menggunakan tupel untuk memecahkan Masalah 11 Proyek 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
    }
}

Sekarang saya bisa menyelesaikan seluruh masalah dengan:

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);
    }
}

Saya bisa saja menggunakan tipe khusus untuk ini, tetapi akan terlihat persis seperti Tuple .

Craig Stuntz
sumber
16

Sintaks tupel C # sangat besar, jadi tupel sulit untuk dideklarasikan. Dan itu tidak memiliki pencocokan pola, jadi mereka juga menyakitkan untuk digunakan.

Namun terkadang, Anda hanya menginginkan pengelompokan ad-hoc objek tanpa membuat kelas untuk itu. Misalnya, saya ingin menggabungkan daftar, tetapi saya menginginkan dua nilai, bukan satu:

// 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));

Alih-alih menggabungkan sekumpulan nilai menjadi satu hasil, mari memperluas satu hasil menjadi sekumpulan nilai. Cara termudah untuk menulis fungsi ini adalah:

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;
    }
}

fmengubah beberapa status menjadi tupel. Kami mengembalikan nilai pertama dari tupel dan mengatur status baru kami ke nilai kedua. Ini memungkinkan kami untuk mempertahankan status selama penghitungan.

Anda menggunakannya seperti:

// 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();

evenscukup mudah, tetapi fibssedikit lebih pintar. Ini statesebenarnya adalah tupel yang masing-masing memegang fib (n-2) dan fib (n-1).

Juliet
sumber
4
+1 Tuple.Create adalah singkatan praktis untuknew Tuple<Guid,string,...>
AaronLS
@Juliet What the use of State keyword
irfandar
7

Saya tidak suka penyalahgunaannya, karena mereka menghasilkan kode yang tidak menjelaskan dirinya sendiri, tetapi mereka mengagumkan untuk mengimplementasikan kunci gabungan on-the-fly, karena mereka mengimplementasikan IStructuralEquatable dan IStructuralComparable (untuk digunakan baik untuk pencarian maupun pemesanan tujuan).

Dan mereka menggabungkan semua kode hash item mereka, secara internal; misalnya, inilah GetHashCode Tuple (diambil dari ILSpy):

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

Tupel sangat bagus untuk melakukan beberapa operasi IO asinkron pada satu waktu dan mengembalikan semua nilai secara bersamaan. Berikut adalah contoh melakukannya dengan dan tanpa Tuple. Tuple sebenarnya dapat membuat kode Anda lebih jelas!

Tanpa (bersarang buruk!):

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);
                                            }
                                        });
                            }
                        });
            }
        });

Dengan 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);
            }
        });

Jika Anda menggunakan fungsi anonim dengan tipe tersirat , maka Anda tidak membuat kode kurang jelas dengan menggunakan Tuple. Retuning Tuple dari metode? Gunakan dengan hemat ketika kejelasan kode adalah kuncinya, menurut pendapat saya. Saya tahu pemrograman fungsional di C # sulit untuk ditolak, tetapi kita harus mempertimbangkan semua programmer C # yang "berorientasi objek".

AndyClaw
sumber
5

Tuple banyak digunakan dalam bahasa fungsional yang dapat melakukan lebih banyak hal dengannya, sekarang F # adalah bahasa .net 'resmi' Anda mungkin ingin beroperasi dengannya dari C # dan meneruskannya di antara kode yang ditulis dalam dua bahasa.

Mant101
sumber
Tuple juga dibangun dalam tipe untuk beberapa bahasa skrip populer seperti Python dan Ruby (yang juga memiliki implementasi .Net untuk interop ... IronPython / Ruby).
MutantNinjaCodeMonkey
5

Saya cenderung menghindari Tupleuntuk sebagian besar skenario karena itu merusak keterbacaan. Namun, Tupleberguna saat Anda perlu mengelompokkan data yang tidak terkait.

Misalnya, Anda memiliki daftar mobil dan kota tempat pembeliannya:

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

Anda ingin menggabungkan hitungan untuk setiap mobil per kota:

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

Untuk melakukan ini, Anda membuat file Dictionary. Anda punya beberapa pilihan:

  1. Buat a Dictionary<string, Dictionary<string, int>>.
  2. Buat a Dictionary<CarAndCity, int>.
  3. Buat a Dictionary<Tuple<string, string>, int>.

Keterbacaan hilang dengan opsi pertama. Ini akan meminta Anda untuk menulis lebih banyak kode.

Opsi kedua berfungsi dan ringkas, tetapi mobil dan kota tidak benar-benar terkait dan mungkin tidak tergabung dalam satu kelas.

Opsi ketiga ringkas dan bersih. Ini penggunaan yang baik Tuple.

John Kurlak
sumber
4

Beberapa contoh di luar kepala saya:

  • Lokasi X dan Y (dan Z jika Anda suka)
  • a Lebar dan Tinggi
  • Apa pun yang diukur dari waktu ke waktu

Misalnya Anda tidak ingin menyertakan System.Drawing dalam aplikasi web hanya untuk menggunakan Point / PointF dan Size / SizeF.

James Westgate
sumber
2
Tupleberguna dalam situasi kritis Pointatau SomeVectormungkin berguna saat melakukan operasi grafis. Ini menyoroti dua nilai yang sangat terkait satu sama lain. Saya sering melihat properti bernama StartTime dan EndTime ketika membaca kode, tetapi bahkan lebih baik daripada tanggal dan durasi, Tuple memaksa Anda untuk mempertimbangkan kedua nilai setiap kali Anda beroperasi di area logika bisnis Anda ini. Atau mengembalikan "hei, data telah berubah (bool), inilah data (jenis lain)" dalam proses berat alih-alih melalui pengikatan intensif.
Léon Pelletier
3

Anda harus sangat berhati-hati dalam menggunakan Tupledan mungkin berpikir dua kali sebelum melakukan ini. Dari pengalaman saya sebelumnya, saya menemukan bahwa menggunakan Tuplemembuat kode sangat sulit untuk dibaca dan didukung di masa depan. Beberapa waktu yang lalu, saya harus memperbaiki beberapa kode di mana tupel digunakan hampir di mana-mana. Alih-alih memikirkan model objek yang tepat, mereka hanya menggunakan tupel. Itu mimpi buruk ... terkadang aku ingin membunuh orang yang menulis kode ...

Tidak ingin mengatakan bahwa Anda tidak boleh menggunakan Tupledan itu jahat atau sesuatu dan saya seratus persen yakin ada beberapa tugas di mana Tuplekandidat terbaik untuk digunakan, tetapi mungkin Anda harus berpikir lagi, apakah Anda BENAR-BENAR membutuhkannya ?

Tuan Labu
sumber
1

Penggunaan terbaik untuk Tuple yang saya temukan adalah ketika perlu mengembalikan lebih dari 1 jenis objek dari suatu metode, Anda tahu apa jenis dan nomor objek itu, dan ini bukan daftar yang panjang.

Alternatif sederhana lainnya akan menggunakan parameter 'keluar'

private string MyMethod(out object)

atau membuat Kamus

Dictionary<objectType1, objectType2>

Namun, menggunakan Tuple akan menghemat pembuatan objek 'keluar' atau harus mencari entri dalam kamus;

sidjames
sumber
1

Baru saja menemukan solusi dari salah satu masalah saya di Tuple. Ini seperti mendeklarasikan kelas dalam lingkup suatu metode, tetapi dengan deklarasi malas dari nama bidangnya. Anda beroperasi dengan koleksi tupel, contoh tunggalnya, dan kemudian membuat koleksi tipe anonim dengan nama bidang yang diperlukan, berdasarkan tupel Anda. Ini menghindari Anda dari membuat kelas baru untuk tujuan ini.

Tugasnya adalah menulis respons JSON dari LINQ tanpa kelas tambahan apa pun:

 //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);

Karena kita bisa melakukan ini dengan mendeklarasikan Class baru untuk grup saya, tetapi ide untuk membuat koleksi anonim tanpa mendeklarasikan class baru.

Alex
sumber
1

Dalam kasus saya, saya harus menggunakan Tuple ketika saya menemukan bahwa kita tidak dapat menggunakan parameter dalam metode asynchronous. Bacalah di sini . Saya juga membutuhkan tipe pengembalian yang berbeda. Jadi saya menggunakan Tuple sebagai gantinya sebagai tipe kembalian saya dan menandai metode tersebut sebagai async.

Contoh kode di bawah ini.

...
...
// 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).
}

Baca lebih lanjut tentang Tuple di sini . Semoga ini membantu.

Amogh Natu
sumber
Saya berasumsi Anda tidak ingin mengembalikan tipe atau Array anonim (atau konten dinamis)
ozzy432836
0

Mengubah bentuk objek saat Anda perlu mengirimnya melintasi kabel atau meneruskan ke lapisan aplikasi yang berbeda dan beberapa objek digabungkan menjadi satu:

Contoh:

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

ExtensionMethod:

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;
    }
Matas Vaitkevicius
sumber
0

Parameter keluar sangat bagus ketika hanya ada beberapa nilai yang perlu dikembalikan, tetapi ketika Anda mulai menemukan 4, 5, 6, atau lebih nilai yang perlu dikembalikan, itu bisa menjadi sulit. Pilihan lain untuk mengembalikan beberapa nilai adalah membuat dan mengembalikan kelas / struktur yang ditentukan pengguna atau menggunakan Tuple untuk mengemas semua nilai yang perlu dikembalikan oleh metode.

Opsi pertama, menggunakan kelas / struktur untuk mengembalikan nilai, sangatlah mudah. Buat saja tipe (dalam contoh ini adalah struktur) seperti ini:

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

Opsi kedua, menggunakan Tuple, adalah solusi yang lebih elegan daripada menggunakan objek yang ditentukan pengguna. Tuple dapat dibuat untuk menampung sejumlah nilai dari berbagai jenis. Selain itu, data yang Anda simpan di Tuple tidak dapat diubah; setelah Anda menambahkan data ke Tuple melalui konstruktor atau metode Buat statis, data tersebut tidak dapat diubah. Tuple dapat menerima hingga dan termasuk delapan nilai terpisah. Jika Anda perlu mengembalikan lebih dari delapan nilai, Anda perlu menggunakan kelas Tuple khusus: Kelas Tuple Saat membuat Tupel dengan lebih dari delapan nilai, Anda tidak dapat menggunakan metode Buat statis — Anda harus menggunakan konstruktor kelas. Beginilah cara Anda membuat Tuple dari 10 nilai integer:

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));

Tentu saja, Anda dapat terus menambahkan lebih banyak Tupel ke akhir setiap Tupel yang disematkan, membuat Tupel ukuran apa pun yang Anda butuhkan.

Kata Chowdary Yashwanth
sumber
0

Hanya untuk pembuatan prototipe - Tupel tidak ada artinya. Ini nyaman untuk menggunakannya tetapi ini hanya jalan pintas! Untuk prototipe - bagus. Pastikan untuk menghapus kode ini nanti.

Mudah untuk menulis, sulit untuk dibaca. Itu tidak memiliki keunggulan yang terlihat atas kelas, kelas dalam, kelas anonim dll.

kelinci 1985
sumber
0

Baiklah saya mencoba 3 cara untuk memecahkan masalah yang sama di C # 7 dan saya telah menemukan kasus penggunaan untuk Tuple.

Bekerja dengan data dinamis dalam proyek web terkadang bisa menyebalkan saat memetakan, dll.

Saya suka cara Tuple secara otomatis dipetakan ke item1, item2, itemN yang tampaknya lebih kuat bagi saya daripada menggunakan indeks array di mana Anda mungkin terjebak pada item di luar indeks atau menggunakan jenis anonim di mana Anda mungkin salah mengeja nama properti.

Rasanya seperti DTO telah dibuat secara gratis hanya dengan menggunakan Tuple dan saya dapat mengakses semua properti menggunakan itemN yang terasa lebih seperti mengetik statis tanpa harus membuat DTO terpisah untuk tujuan itu.

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 };
            }
        }
    }
}
ozzy432836.dll
sumber