C ++ std :: pair C # analog nedir?


284

Ben ilgileniyorum: C # ' std::pairin C ++ analog nedir? System.Web.UI.PairSınıf buldum , ama şablon tabanlı bir şey tercih ederim.

Teşekkür ederim!


11
Bir süre önce aynı isteği aldım, ancak daha çok düşündüğümde, sadece kendi eşleştirme sınıfınızı, genel "Birinci" ve "İkinci" yerine açık sınıf türleri ve alanları ile yuvarlamak isteyebilirsiniz. Kodunuzu daha okunaklı hale getirir. Bir eşleştirme sınıfı 4 satır kadar az olabilir, bu nedenle genel bir Pair <T, U> sınıfını yeniden kullanarak fazla tasarruf yapmazsınız ve kodunuz daha okunabilir olacaktır.
Mark Lakata

Yanıtlar:


325

Tuples .NET4.0'dan beri mevcuttur ve jenerikleri destekler:

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

Önceki sürümlerde System.Collections.Generic.KeyValuePair<K, V>aşağıdaki gibi bir çözüm veya kullanabilirsiniz :

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

Ve şu şekilde kullanın:

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

Bu çıktılar:

test
2

Veya bu zincirlenmiş çiftler bile:

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

Bu çıktı:

test
12
true

Eşit bir yöntem ekleme hakkındaki yazımı görün
Andrew Stein

Tuple <> artık daha iyi bir çözüm.
dkantowitz

6
Genel sınıfa ait tür parametreleri bir nesne oluşturma ifadesinde (kurucu çağrısı) çıkarılamadığından, BCL yazarları, jenerik olmayan bir yardımcı sınıf olarak adlandırılırlar Tuple. Bu yüzden Tuple.Create("Hello", 4)hangisinin daha kolay olduğunu söyleyebilirsiniz new Tuple<string, int>("Hello", 4). (Bu arada, .NET4.0 2010'dan beri burada.)
Jeppe Stig Nielsen

4
Büyük ve değer semantiği ile Tuple<>uyguladığınızı unutmayın . Kendi tuple'lerinizi uygularken unutmayın. EqualsGetHashCode
nawfal

Bu eşittir ve GetHashCode nedeniyle kırılmış
julx

90

System.Web.UIPairASP.NET 1.1'de dahili bir ViewState yapısı olarak yoğun bir şekilde kullanıldığı için sınıf içerdi .

Ağustos 2017 Güncelleştirmesi: C # 7.0 / .NET Framework 4.7, System.ValueTupleyapıyı kullanarak adlandırılmış öğeler içeren bir Tuple bildirmek için bir sözdizimi sağlar .

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

daha fazla sözdizimi örneği için MSDN'ye bakın .

Haziran 2012 Güncellemesi: Tuples 4.0 sürümünden beri .NET'in bir parçası olmuştur.

İşte içerme in.NET4.0 açıklayan önceki bir makale jenerik için ve destek:

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

2
Tuples'ın salt okunur olduğunu unutmayın. Yani, bunu yapamazsınız:tuple.Item1 = 4;
skybluecodeflier

2
Tuples tam olarak aradığım şeydi. Teşekkürler.
gligoran

38

Maalesef yok. System.Collections.Generic.KeyValuePair<K, V>Birçok durumda kullanabilirsiniz .

Alternatif olarak, en azından yerel olarak tuple'ları işlemek için anonim türleri kullanabilirsiniz:

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

Son alternatif kendi sınıfını yaratmaktır.


2
Açık olmak gerekirse, anonim türler de salt okunurdur - msdn .
bsegraves


11

Bazı cevaplar yanlış görünüyor,

  1. (a, b) ve (a, c) çiftlerini nasıl saklayacağına sözlüğü kullanamazsınız. Çiftler kavramı, anahtar ve değerlerin ilişkisel olarak bakılması ile karıştırılmamalıdır.
  2. Yukarıdaki kodun çoğu şüpheli görünüyor

İşte çift sınıfım

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

İşte bazı test kodu:

[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
IEquatable uygulamıyorsanız boks alırsınız. Sınıfınızı doğru bir şekilde tamamlamak için yapılması gereken daha çok iş var.
Jack

8

Sözlükler ve benzerleri ile ilgili ise, System.Collections.Generic.KeyValuePair <TKey, TValue> 'ı arıyorsunuz.


3

Neyi başarmak istediğinize bağlı olarak, KeyValuePair'i denemek isteyebilirsiniz .

Bir girdinin anahtarını değiştirememeniz elbette tüm girdiyi yeni bir KeyValuePair örneğiyle değiştirerek düzeltilebilir.



2

Ben hemen şimdi hızlı bir google sonra aynı soruyu soruyordum .NET içinde System.Web.UI ^ ~ ^ dışında bir çift sınıf olduğunu bulunduhttp://msdn.microsoft.com/en-us/library/system.web.ui.pair.aspx ) İyilik, koleksiyon çerçevesi yerine neden oraya koyduklarını bilir


System.Web.UI.Pair'i biliyorum. Gerçi genel sınıf istedim.
Alexander Prokofyev

System.Web.UI.Pair mühürlendi. Ondan türeyemezsiniz (tip güvenli erişimciler eklemek istiyorsanız).
Martin Vobr

2

.NET 4.0'dan beri System.Tuple<T1, T2>sınıfınız var:

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

@Alexander, Tuple'da .NET 3.5 belgelerine
Serge Mikhailov

Altta şöyle diyorlar: Sürüm Bilgileri NET Framework Destekleyen: 4
Alexander Prokofyev

2
@Alexander: Tamam, doğru. (Yine de bu sayfayı neden .NET 3.5'e özgü hale getirdiklerini merak etmeme rağmen)
Serge Mikhailov

2

Ben tipik olarak Tuplekendi genel sarmalayıcı içine sınıf aşağıdaki gibi genişletmek :

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

ve şu şekilde kullanın:

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

Yukarıdaki işe almak için (Ben bir sözlük anahtarı olarak bir çift gerekiyordu). Eklemek zorunda kaldım:

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

ve bunu yaptıktan sonra

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

derleyici uyarısını bastırmak için.


1
Bundan daha iyi bir karma kod algoritması bulmalısınız, 37 + 23 * (h1 + 23 * (h2 + 23 * (h3 + ...))) kullanmayı deneyin (B, A) ), yani. yeniden sıralamanın kod üzerinde bir etkisi olacaktır.
Lasse V. Karlsen

Yorum kabul edildi .. Benim durumumda sadece derleyici azalan bastırmaya çalışıyordum ve yine de T bir String ve U an Int32 ...
Andrew Stein

1

PowerCollections kütüphanesi (daha önce Wintellect'ten temin edilebilir, ancak şimdi Codeplex @ http ://powercollections.codeplex.com'da barındırılmaktadır ) genel bir Pair yapısına sahiptir.


1

Özel sınıf veya .Net 4.0 Tuples dışında, C # 7.0'dan beri, bu durumda kullanılabilecek bir yapı olan ValueTuple adlı yeni bir özellik var. Yazmak yerine:

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

ve erişim değerleri üzerinden t.Item1ve t.Item2, sadece böyle yapabilirsiniz:

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

ya da:

(var message, var count) = ("Hello", 4);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.