Chỉ thêm mặt hàng duy nhất vào danh sách


84

Tôi đang thêm các thiết bị từ xa vào danh sách khi chúng tự thông báo trên mạng. Tôi chỉ muốn thêm thiết bị vào danh sách nếu nó chưa được thêm trước đó.

Các thông báo sẽ đến với trình nghe ổ cắm không đồng bộ nên mã để thêm thiết bị có thể được chạy trên nhiều luồng. Tôi không chắc mình đang làm gì sai nhưng không có trường hợp nào tôi cố gắng tôi kết thúc với sự trùng lặp. Đây là những gì tôi hiện có .....

lock (_remoteDevicesLock)
{
    RemoteDevice rDevice = (from d in _remoteDevices
                            where d.UUID.Trim().Equals(notifyMessage.UUID.Trim(), StringComparison.OrdinalIgnoreCase)
                            select d).FirstOrDefault();
     if (rDevice != null)
     {
         //Update Device.....
     }
     else
     {
         //Create A New Remote Device
         rDevice = new RemoteDevice(notifyMessage.UUID);
         _remoteDevices.Add(rDevice);
     }
}

Định nghĩa cho là RemoteDevicegì?
— pstrjds

cho mục đích gỡ lỗi, bạn có thể mở rộng lớp _remoteDevices của mình với trường dấu thời gian, _remoteDevices.lastSeen = bây giờ không?
— Beth

Câu trả lời:


154

Nếu yêu cầu của bạn là không có bản sao, bạn nên sử dụng HashSet .

HashSet.Add sẽ trả về false khi mục đó đã tồn tại (nếu điều đó thậm chí quan trọng với bạn).

Bạn có thể sử dụng hàm tạo mà @pstrjds liên kết đến bên dưới (hoặc tại đây ) để xác định toán tử bình đẳng hoặc bạn sẽ cần triển khai các phương thức bình đẳng trong RemoteDevice( GetHashCode& Equals).


3
Đã sắp thêm câu trả lời này. Bạn có thể sử dụng quá tải này để xác định và so sánh- - msdn.microsoft.com/en-us/library/bb359100(v=vs.100).aspx
— pstrjds

11
Một lưu ý quan trọng ở đây là HashSet không được đảm bảo tuân theo thứ tự chèn. Vì vậy, nếu thứ tự là quan trọng (các mục cần xuất hiện trong danh sách theo thứ tự như bạn đặt chúng, như những gì xảy ra với List<T>) thì HashSet không hoạt động tốt.
— JulianR

Rất cám ơn vì điều này. Tôi vẫn cần giữ khóa để đảm bảo an toàn cho luồng hay có cách nào tốt hơn?
— Oli

2
@Oli Bạn cần giữ khóa, nhưng thao tác sẽ nhanh hơn nhiều , vì vậy họ sẽ không phải chờ đợi nhau nhiều. Không có ConcurrentSetlớp học, thật không may. Tuy nhiên, có một ConcurrentDictionarylớp, vì vậy bạn có thể sử dụng lớp đó, lưu trữ các giá trị của bạn dưới dạng các khóa và chỉ lưu trữ nulltrong các giá trị.
— Servy

1
@Oli: Nếu tôi là bạn, tôi sẽ đăng một câu hỏi khác để giải quyết vấn đề đó (với nguồn đầy đủ của cả GetHashCode & Equals, cùng với các trường hợp chúng khớp với nhau khi bạn không mong đợi).
— Austin Salonen

22
//HashSet allows only the unique values to the list
HashSet<int> uniqueList = new HashSet<int>();

var a = uniqueList.Add(1);
var b = uniqueList.Add(2);
var c = uniqueList.Add(3);
var d = uniqueList.Add(2); // should not be added to the list but will not crash the app

//Dictionary allows only the unique Keys to the list, Values can be repeated
Dictionary<int, string> dict = new Dictionary<int, string>();

dict.Add(1,"Happy");
dict.Add(2, "Smile");
dict.Add(3, "Happy");
dict.Add(2, "Sad"); // should be failed // Run time error "An item with the same key has already been added." App will crash

//Dictionary allows only the unique Keys to the list, Values can be repeated
Dictionary<string, int> dictRev = new Dictionary<string, int>();

dictRev.Add("Happy", 1);
dictRev.Add("Smile", 2);
dictRev.Add("Happy", 3); // should be failed // Run time error "An item with the same key has already been added." App will crash
dictRev.Add("Sad", 2);

16

Giống như câu trả lời được chấp nhận cho biết HashSet không có đơn đặt hàng. Nếu thứ tự quan trọng, bạn có thể tiếp tục sử dụng Danh sách và kiểm tra xem nó có chứa mặt hàng hay không trước khi thêm vào.

if (_remoteDevices.Contains(rDevice))
    _remoteDevices.Add(rDevice);

Thực hiện List.Contains () trên một lớp / đối tượng tùy chỉnh yêu cầu triển khai IEquatable<T>trên lớp tùy chỉnh hoặc ghi đè Equals. Bạn cũng nên thực hiện GetHashCodetrong lớp. Đây là theo tài liệu tại https://msdn.microsoft.com/en-us/library/ms224763.aspx

public class RemoteDevice: IEquatable<RemoteDevice>
{
    private readonly int id;
    public RemoteDevice(int uuid)
    {
        id = id
    }
    public int GetId
    {
        get { return id; }
    }

    // ...

    public bool Equals(RemoteDevice other)
    {
        if (this.GetId == other.GetId)
            return true;
        else
            return false;
    }
    public override int GetHashCode()
    {
        return id;
    }
}

xin chào thx nhưng điều gì sẽ xảy ra nếu bạn không thể ghi đè vì tôi đang sử dụng tham chiếu đến mã của người khác - người ta làm gì ở đây?
— BKSpurgeon
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 cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.