Apa itu analog C # dari C ++ std :: pair?


284

Saya tertarik: Apakah analog C # std::pairdalam C ++? Saya menemukan System.Web.UI.Pairkelas, tetapi saya lebih suka sesuatu yang berbasis template.

Terima kasih!


11
Saya memiliki permintaan yang sama beberapa waktu yang lalu, tetapi semakin saya memikirkannya, Anda mungkin ingin hanya menggulung kelas pasangan Anda sendiri, dengan jenis dan bidang kelas eksplisit alih-alih generik "Pertama" dan "Kedua". Itu membuat kode Anda lebih mudah dibaca. Kelas pasangan bisa hanya 4 baris, jadi Anda tidak banyak menghemat dengan menggunakan kembali kelas Pair <T, U> generik dan kode Anda akan lebih mudah dibaca.
Mark Lakata

Jawaban:


325

Tuples tersedia sejak .NET4.0 dan dukungan generik:

Tuple<string, int> t = new Tuple<string, int>("Hello", 4);

Dalam versi sebelumnya, Anda dapat menggunakan System.Collections.Generic.KeyValuePair<K, V>atau solusi seperti berikut:

public class Pair<T, U> {
    public Pair() {
    }

    public Pair(T first, U second) {
        this.First = first;
        this.Second = second;
    }

    public T First { get; set; }
    public U Second { get; set; }
};

Dan gunakan seperti ini:

Pair<String, int> pair = new Pair<String, int>("test", 2);
Console.WriteLine(pair.First);
Console.WriteLine(pair.Second);

Output ini:

test
2

Atau bahkan pasangan berantai ini:

Pair<Pair<String, int>, bool> pair = new Pair<Pair<String, int>, bool>();
pair.First = new Pair<String, int>();
pair.First.First = "test";
pair.First.Second = 12;
pair.Second = true;

Console.WriteLine(pair.First.First);
Console.WriteLine(pair.First.Second);
Console.WriteLine(pair.Second);

Keluaran itu:

test
12
true

Lihat posting saya tentang menambahkan metode Setara
Andrew Stein

Tuple <> sekarang merupakan solusi yang lebih baik.
dkantowitz

6
Karena parameter tipe milik kelas generik tidak dapat disimpulkan dalam ekspresi pembuatan objek (panggilan konstruktor), penulis BCL membuat kelas pembantu non-generik yang disebut Tuple. Karena itu Anda dapat mengatakan Tuple.Create("Hello", 4)yang sedikit lebih mudah daripada new Tuple<string, int>("Hello", 4). (Omong-omong, .NET4.0 sudah ada di sini sejak 2010.)
Jeppe Stig Nielsen

4
Pikiran Anda Tuple<>menerapkan solid Equalsdan GetHashCodedengan semantik nilai yang hebat. Perlu diingat saat menerapkan tupel Anda sendiri.
nawfal

Ini jelas rusak karena Equals dan GetHashCode
julx

90

System.Web.UIberisi Pairkelas karena itu banyak digunakan dalam ASP.NET 1.1 sebagai struktur ViewState internal.

Pembaruan Agustus 2017: C # 7.0 / .NET Framework 4.7 menyediakan sintaks untuk mendeklarasikan Tuple dengan item bernama menggunakan System.ValueTuplestruct.

//explicit Item typing
(string Message, int SomeNumber) t = ("Hello", 4);
//or using implicit typing 
var t = (Message:"Hello", SomeNumber:4);

Console.WriteLine("{0} {1}", t.Message, t.SomeNumber);

lihat MSDN untuk lebih banyak contoh sintaks.

Pembaruan Juni 2012: Tuples telah menjadi bagian dari .NET sejak versi 4.0.

Berikut ini adalah artikel sebelumnya yang menguraikan inklusi di.NET4.0 dan dukungan untuk obat generik:

Tuple<string, int> t = new Tuple<string, int>("Hello", 4);

2
Perhatikan bahwa Tuples hanya-baca. Artinya, Anda tidak dapat melakukan ini:tuple.Item1 = 4;
skybluecodeflier

2
Tuples persis seperti yang saya cari. Terima kasih.
gligoran

38

Sayangnya tidak ada. Anda dapat menggunakannya System.Collections.Generic.KeyValuePair<K, V>dalam banyak situasi.

Atau, Anda dapat menggunakan jenis anonim untuk menangani tupel, setidaknya secara lokal:

var x = new { First = "x", Second = 42 };

Alternatif terakhir adalah membuat kelas sendiri.


2
Supaya jelas, jenis anonim juga hanya baca - msdn .
bsegraves


11

Beberapa jawaban sepertinya salah,

  1. Anda tidak dapat menggunakan kamus bagaimana cara menyimpan pasangan (a, b) dan (a, c). Konsep Pairs jangan dibingungkan dengan asosiatif mencari kunci dan nilai-nilai
  2. banyak kode di atas tampaknya mencurigakan

Inilah kelas pasangan saya

public class Pair<X, Y>
{
    private X _x;
    private Y _y;

    public Pair(X first, Y second)
    {
        _x = first;
        _y = second;
    }

    public X first { get { return _x; } }

    public Y second { get { return _y; } }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        if (obj == this)
            return true;
        Pair<X, Y> other = obj as Pair<X, Y>;
        if (other == null)
            return false;

        return
            (((first == null) && (other.first == null))
                || ((first != null) && first.Equals(other.first)))
              &&
            (((second == null) && (other.second == null))
                || ((second != null) && second.Equals(other.second)));
    }

    public override int GetHashCode()
    {
        int hashcode = 0;
        if (first != null)
            hashcode += first.GetHashCode();
        if (second != null)
            hashcode += second.GetHashCode();

        return hashcode;
    }
}

Berikut ini beberapa kode tes:

[TestClass]
public class PairTest
{
    [TestMethod]
    public void pairTest()
    {
        string s = "abc";
        Pair<int, string> foo = new Pair<int, string>(10, s);
        Pair<int, string> bar = new Pair<int, string>(10, s);
        Pair<int, string> qux = new Pair<int, string>(20, s);
        Pair<int, int> aaa = new Pair<int, int>(10, 20);

        Assert.IsTrue(10 == foo.first);
        Assert.AreEqual(s, foo.second);
        Assert.AreEqual(foo, bar);
        Assert.IsTrue(foo.GetHashCode() == bar.GetHashCode());
        Assert.IsFalse(foo.Equals(qux));
        Assert.IsFalse(foo.Equals(null));
        Assert.IsFalse(foo.Equals(aaa));

        Pair<string, string> s1 = new Pair<string, string>("a", "b");
        Pair<string, string> s2 = new Pair<string, string>(null, "b");
        Pair<string, string> s3 = new Pair<string, string>("a", null);
        Pair<string, string> s4 = new Pair<string, string>(null, null);
        Assert.IsFalse(s1.Equals(s2));
        Assert.IsFalse(s1.Equals(s3));
        Assert.IsFalse(s1.Equals(s4));
        Assert.IsFalse(s2.Equals(s1));
        Assert.IsFalse(s3.Equals(s1));
        Assert.IsFalse(s2.Equals(s3));
        Assert.IsFalse(s4.Equals(s1));
        Assert.IsFalse(s1.Equals(s4));
    }
}

3
Jika Anda tidak mengimplementasikan IEquatable, Anda akan mendapatkan tinju. Ada banyak pekerjaan yang harus dilakukan untuk menyelesaikan kelas Anda dengan benar.
Jack

8

Jika ini tentang kamus dan sejenisnya, Anda sedang mencari System.Collections.Generic.KeyValuePair <TKey, TValue>.


3

Bergantung pada apa yang ingin Anda capai, Anda mungkin ingin mencoba KeyValuePair .

Fakta bahwa Anda tidak dapat mengubah kunci entri tentu saja dapat diperbaiki dengan hanya mengganti seluruh entri dengan contoh baru KeyValuePair.


3

Saya membuat implementasi C # dari Tuples, yang memecahkan masalah secara umum untuk antara dua dan lima nilai - inilah posting blog , yang berisi tautan ke sumbernya.


2

Saya mengajukan pertanyaan yang sama sekarang setelah google cepat saya menemukan bahwa Ada kelas pasangan di. NET kecuali di System.Web.UI ^ ~ ^ (http://msdn.microsoft.com/en-us/library/system.web.ui.pair.aspx ) kebaikan tahu mengapa mereka meletakkannya di sana alih-alih kerangka koleksi


Saya tahu tentang System.Web.UI.Pair. Ingin kelas generik.
Alexander Prokofyev

System.Web.UI.Pair disegel. Anda tidak dapat mengambil darinya (jika Anda ingin menambahkan tipe accessors aman).
Martin Vobr

2

Sejak .NET 4.0 Anda memiliki System.Tuple<T1, T2>kelas:

// pair is implicitly typed local variable (method scope)
var pair = System.Tuple.Create("Current century", 21);

@Alexander, Anda dapat dengan mudah melihat ke dalam . NET 3.5 dokumen di Tuple
Serge Mikhailov

Di bagian bawah, mereka mengatakan: Versi Informasi NET Framework Didukung dalam: 4
Alexander Prokofyev

2
@Alexander: Oke, benar. (Meskipun itu membuat saya bertanya-tanya mengapa mereka membuat halaman ini. NET 3.5-spesifik)
Serge Mikhailov

2

Saya biasanya memperluas Tuplekelas ke bungkus generik saya sendiri sebagai berikut:

public class Statistic<T> : Tuple<string, T>
{
    public Statistic(string name, T value) : base(name, value) { }
    public string Name { get { return this.Item1; } }
    public T Value { get { return this.Item2; } }
}

dan gunakan seperti ini:

public class StatSummary{
      public Statistic<double> NetProfit { get; set; }
      public Statistic<int> NumberOfTrades { get; set; }

      public StatSummary(double totalNetProfit, int numberOfTrades)
      {
          this.TotalNetProfit = new Statistic<double>("Total Net Profit", totalNetProfit);
          this.NumberOfTrades = new Statistic<int>("Number of Trades", numberOfTrades);
      }
}

StatSummary summary = new StatSummary(750.50, 30);
Console.WriteLine("Name: " + summary.NetProfit.Name + "    Value: " + summary.NetProfit.Value);
Console.WriteLine("Name: " + summary.NumberOfTrades.Value + "    Value: " + summary.NumberOfTrades.Value);

1

Untuk mendapatkan cara di atas berfungsi (saya membutuhkan pasangan sebagai kunci kamus). Saya harus menambahkan:

    public override Boolean Equals(Object o)
    {
        Pair<T, U> that = o as Pair<T, U>;
        if (that == null)
            return false;
        else
            return this.First.Equals(that.First) && this.Second.Equals(that.Second);
    }

dan begitu saya melakukannya saya juga menambahkan

    public override Int32 GetHashCode()
    {
        return First.GetHashCode() ^ Second.GetHashCode();
    }

untuk menekan peringatan kompiler.


1
Anda harus menemukan algoritma kode hash yang lebih baik daripada itu, coba gunakan 37 + 23 * (h1 + 23 * (h2 + 23 * (h3 + ...))) Ini akan membuat (A, B) berbeda dari (B, A) ), yaitu. penataan ulang akan berpengaruh pada kode.
Lasse V. Karlsen

Komentar adalah diterima .. Dalam kasus saya saya hanya mencoba untuk menekan compiler berkurang, dan lagi pula T adalah String dan U Int32 ...
Andrew Stein


1

Terlepas dari kelas kustom atau .Net 4.0 Tuples, karena C # 7.0 ada fitur baru yang disebut ValueTuple, yang merupakan struct yang dapat digunakan dalam kasus ini. Alih-alih menulis:

Tuple<string, int> t = new Tuple<string, int>("Hello", 4);

dan mengakses nilai melalui t.Item1dan t.Item2, Anda cukup melakukannya seperti itu:

(string message, int count) = ("Hello", 4);

atau bahkan:

(var message, var count) = ("Hello", 4);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.