목록에 고유 항목 만 추가


84

네트워크를 통해 자신을 알리는 원격 장치를 목록에 추가하고 있습니다. 이전에 추가하지 않은 장치 만 목록에 추가하고 싶습니다.

알림은 비동기 소켓 리스너를 통해 전달되므로 장치를 추가하는 코드를 여러 스레드에서 실행할 수 있습니다. 나는 내가 뭘 잘못하고 있는지 확실하지 않지만 내가 시도하는 것과 상관없이 중복으로 끝납니다. 여기 내가 현재 가지고있는 것 .....

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

의 정의는 무엇입니까 RemoteDevice?
pstrjds 2011

디버깅을 위해 타임 스탬프 필드 _remoteDevices.lastSeen = now를 사용하여 _remoteDevices 클래스를 확장 할 수 있습니까?
Beth

답변:


154

요구 사항이 중복되지 않도록하려면 HashSet 을 사용해야합니다 .

HashSet.Add 는 항목이 이미 존재하는 경우 false 를 반환 합니다 (중요한 경우에도).

@pstrjds가 아래 (또는 여기 )에 연결하는 생성자 를 사용하여 같음 연산자를 정의하거나 RemoteDevice( GetHashCode& Equals) 에서 같음 메서드를 구현해야합니다 .


3
이 답변을 추가하려고했습니다. 이 오버로드를 사용하여 비교를 정의 할 수 있습니다. msdn.microsoft.com/en-us/library/bb359100(v=vs.100).aspx
pstrjds

11
여기서 중요한 점은 HashSet이 삽입 순서를 준수한다고 보장되지 않는다는 것입니다. 따라서 순서가 중요한 경우 (항목이에서 발생하는 것과 같이 항목을 넣은 것과 동일한 순서로 목록에 나타나야 함 List<T>) HashSet이 제대로 작동하지 않습니다.
JulianR

감사합니다. 스레드 안전을 위해 잠금을 계속 유지해야합니까? 아니면 더 나은 방법이 있습니까?
Oli

2
@Oli 잠금을 유지해야하지만 작업이 훨씬 빠르기 때문에 서로를 기다리지 않을 것입니다. ConcurrentSet불행히도 수업 이 없습니다 . 그러나 ConcurrentDictionary클래스가 있으므로이를 사용하여 값을 키로 저장 null하고 값에 저장할 수 있습니다.
Servy

1
@Oli : 내가 당신이라면 그 문제를 해결하기 위해 또 다른 질문을 게시 할 것입니다 (GetHashCode & Equals의 전체 소스와 예상치 못한 경우 일치하는 경우 포함).
Austin Salonen 2012

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

수락 된 답변에 따르면 HashSet에는 주문이 없습니다. 주문이 중요한 경우 목록을 계속 사용하고 추가하기 전에 항목이 포함되어 있는지 확인할 수 있습니다.

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

사용자 정의 클래스 / 객체에서 List.Contains ()를 수행하려면 IEquatable<T>사용자 정의 클래스에서 구현 하거나 Equals. GetHashCode클래스 에서도 구현하는 것이 좋습니다 . 이것은 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;
    }
}

안녕 thx 그러나 다른 사람의 코드에 대한 참조를 사용하고 있기 때문에 재정의 할 수 없다면 어떻게해야합니까?
BKSpurgeon 2017 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.