C # analog của C ++ std :: cặp là gì?


284

Tôi quan tâm: Tương tự của C # std::pairtrong C ++ là gì? Tôi đã tìm thấy System.Web.UI.Pairlớp, nhưng tôi thích cái gì đó dựa trên mẫu.

Cảm ơn bạn!


11
Tôi đã có cùng một yêu cầu trước đây, nhưng tôi càng nghĩ về nó, bạn có thể muốn cuộn lớp ghép nối của riêng bạn, với các loại và trường lớp rõ ràng thay vì "Đầu tiên" và "Thứ hai" chung chung. Nó làm cho mã của bạn dễ đọc hơn. Một lớp ghép đôi có thể chỉ có 4 dòng, vì vậy bạn không tiết kiệm được nhiều bằng cách sử dụng lại một lớp <T, U> chung và mã của bạn sẽ dễ đọc hơn.
Mark Lakata

Câu trả lời:


325

Bộ dữ liệu có sẵn kể từ .NET4.0 và hỗ trợ chung chung:

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

Trong các phiên bản trước, bạn có thể sử dụng System.Collections.Generic.KeyValuePair<K, V>hoặc một giải pháp như sau:

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

Và sử dụng nó như thế này:

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

Kết quả này:

test
2

Hoặc thậm chí cặp xích này:

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

Đó là đầu ra:

test
12
true

Xem bài đăng của tôi về việc thêm phương thức Equals
Andrew Stein

Tuple <> bây giờ là một giải pháp tốt hơn.
dkantowitz

6
Do các tham số kiểu thuộc về lớp chung không thể được suy ra trong biểu thức tạo đối tượng (lệnh gọi hàm tạo), nên các tác giả của BCL đã tạo ra một lớp trình trợ giúp không chung chung được gọi Tuple. Do đó bạn có thể nói Tuple.Create("Hello", 4)cái nào dễ hơn một chút new Tuple<string, int>("Hello", 4). (Nhân tiện, .NET4.0 đã ở đây từ năm 2010)
Jeppe Stig Nielsen

4
Tâm trí bạn Tuple<>thực hiện vững chắc EqualsGetHashCodevới ngữ nghĩa giá trị đó là tuyệt vời. Hãy ghi nhớ khi thực hiện bộ dữ liệu của riêng bạn.
nawfal

Điều này rõ ràng đã bị phá vỡ vì Equals và GetHashCode
julx

90

System.Web.UIchứa Pairlớp vì nó được sử dụng nhiều trong ASP.NET 1.1 như một cấu trúc ViewState bên trong.

Cập nhật tháng 8 năm 2017: C # 7.0 / .NET Framework 4.7 cung cấp cú pháp để khai báo Tuple với các mục được đặt tên bằng cách sử dụng 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);

xem MSDN để biết thêm ví dụ cú pháp.

Cập nhật tháng 6 năm 2012: Tuples đã là một phần của .NET kể từ phiên bản 4.0.

Đây là một bài viết trước đó mô tả sự bao gồm trong .NET4.0 và hỗ trợ cho thuốc generic:

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

2
Lưu ý rằng Tuples là chỉ đọc. Đó là, bạn không thể làm điều này:tuple.Item1 = 4;
skybluecodef trước

2
Tuples chính xác là những gì tôi đang tìm kiếm. Cảm ơn.
gligoran

38

Thật không may, không có. Bạn có thể sử dụng System.Collections.Generic.KeyValuePair<K, V>trong nhiều tình huống.

Ngoài ra, bạn có thể sử dụng các loại ẩn danh để xử lý các bộ dữ liệu, ít nhất là cục bộ:

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

Thay thế cuối cùng là tạo một lớp riêng.


2
Để rõ ràng, các loại ẩn danh cũng chỉ đọc - msd .
bsegraves


11

Một số câu trả lời có vẻ sai,

  1. bạn không thể sử dụng từ điển làm thế nào để lưu trữ các cặp (a, b) và (a, c). Khái niệm cặp không nên bị nhầm lẫn với tra cứu kết hợp của khóa và giá trị
  2. rất nhiều đoạn mã trên có vẻ đáng ngờ

Đây là lớp học cặp của tôi

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

Đây là một số mã kiểm tra:

[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
Nếu bạn không thực hiện IEquitable, bạn sẽ nhận được quyền anh. Có nhiều việc phải làm để hoàn thành lớp học của bạn một cách chính xác.
Jack

8

Nếu đó là về từ điển và những thứ tương tự, bạn đang tìm System.Collections.Generic.KeyValuePair <TKey, TValue>.


3

Tùy thuộc vào những gì bạn muốn thực hiện, bạn có thể muốn dùng thử KeyValuePair .

Thực tế là bạn không thể thay đổi khóa của một mục nhập tất nhiên có thể được sửa chữa bằng cách thay thế toàn bộ mục nhập bằng một phiên bản mới của KeyValuePair.



2

Tôi đã hỏi cùng một câu hỏi ngay sau khi google nhanh chóng tôi thấy rằng có một lớp cặp trong .NET ngoại trừ nó trong System.Web.UI ^ ~ ^ (http://msdn.microsoft.com/en-us/l Library / system.web.ui.pair.aspx ) lòng tốt biết tại sao họ đặt nó ở đó thay vì khung bộ sưu tập


Tôi biết về System.Web.UI.Pair. Muốn lớp chung mặc dù.
Alexander Prokofyev

System.Web.UI.Pair được niêm phong. Bạn không thể lấy được từ nó (trong trường hợp bạn muốn thêm loại truy cập an toàn).
Martin Vobr

2

Kể từ .NET 4.0, bạn có System.Tuple<T1, T2>lớp:

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

@Alexander, bạn có thể dễ dàng xem xét các tài liệu .NET 3.5 trên Tuple
Serge Mikhailov

Ở phía dưới, họ nói: Khung thông tin phiên bản NET được hỗ trợ trong: 4
Alexander Prokofyev

2
@Alexander: OK, đúng rồi. (Mặc dù điều đó khiến tôi tự hỏi tại sao họ lại tạo trang này .NET 3.5 cụ thể)
Serge Mikhailov

2

Tôi thường mở rộng Tuplelớp vào trình bao bọc chung của riêng mình như sau:

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

và sử dụng nó như vậy:

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

Để có được những thứ trên để làm việc (tôi cần một cặp làm chìa khóa của từ điển). Tôi đã phải thê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);
    }

và một khi tôi đã làm điều đó tôi cũng thêm

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

để ngăn chặn một cảnh báo trình biên dịch.


1
Bạn nên tìm một thuật toán mã băm tốt hơn thế, hãy thử sử dụng 37 + 23 * (h1 + 23 * (h2 + 23 * (h3 + ...))) Điều này sẽ làm cho (A, B) khác biệt với (B, A ), I E. sắp xếp lại sẽ có ảnh hưởng đến mã.
Lasse V. Karlsen

Nhận xét được chấp nhận .. Trong trường hợp của tôi, tôi chỉ cố gắng triệt tiêu trình biên dịch suy yếu, và dù sao thì T là Chuỗi và U là Int32 ...
Andrew Stein


1

Ngoài lớp tùy chỉnh hoặc .Net 4.0 Tuples, vì C # 7.0 còn có một tính năng mới gọi là ValueTuple, đây là một cấu trúc có thể được sử dụng trong trường hợp này. Thay vì viết:

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

và truy cập các giá trị thông qua t.Item1t.Item2, bạn có thể chỉ cần làm như vậy:

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

hoặc thậm chí:

(var message, var count) = ("Hello", 4);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.