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!

Alexander Prokofyev
sumber
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
Jorge Ferreira
sumber
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);
Jay Walker
sumber
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.

Konrad Rudolph
sumber
2
Supaya jelas, jenis anonim juga hanya baca - msdn .
bsegraves
21

C # memiliki tupel pada versi 4.0.

Kenan EK
sumber
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));
    }
}
Antony
sumber
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>.

OregonGhost
sumber
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.

Grimtron
sumber
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.

Erik Forbes
sumber
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


sumber
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);
Serge Mikhailov
sumber
@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);
parlemen
sumber
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.

Andrew Stein
sumber
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);
Pawel Gradecki
sumber