How to test _set.Contains(obj), when _set is HashSet<T1>, obj isT2, and T1, T2 both implement same interface?

StackOverflow https://stackoverflow.com/questions/22934328

  •  29-06-2023
  •  | 
  •  

Question

I must implement an ObservableHashSet<T> that can quickly (O(1)) test for object existence:

public class ObservableHashSet<T> : ObservableCollection<T>{
    readonly ISet<T> _set = new HashSet<T>();

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e){
        base.OnCollectionChanged(e);
        if (e.Action == NotifyCollectionChangedAction.Move) return;

        if (e.OldItems != null)
            foreach (var old in e.OldItems.Cast<T>())
                _set.Remove(old.GetHashable());

        if (e.NewItems == null) return;

        foreach (var nu in e.NewItems.Cast<T>()) _set.Add(nu.GetHashable());
    }

    public bool QuickContains(T obj){ return _set.Contains(obj); }
}

Now say we have two types, both implement same interface:

IDevice
  ├── ActualDevice
  └── DeviceClass

and the interface is:

public interface IDevice {
    string Vendor { get; set; }
    string Name { get; set; }
}

I need a way to quickly (O(1)) test for certain ActualDevice existence in a list of DeviceClasss (HashSet<DeviceClass>). So how can I change the ObservableHashSet<T>.QuickContains(T obj) function above to allow it? so I'd be able to do something like this:

var classesList = new ObservableHashSet<DeviceClass>(someDataSource);
ActualDevice actualDevice = GetTheDevice();
MessageBox.Show(classesList.QuickContains(actualDevice) ? "Exists!" : "Missing...");
Was it helpful?

Solution

I'd make the item type of the HashSet<T> a class that only contains the data that you base the equality test on. At the moment you are trying to make a DeviceClass compare equal to an ActualDevice which seems odd.

My understanding is that you want to test whether an ActualDevice is associated with one of many DeviceClass'es. You could do it like this:

class DeviceClassKey : IEquatable<DeviceClassKey> {

 //Data members here
 int DeviceClassID; /* just an example */

 public static DeviceClassKey FromDeviceClass(DeviceClass dc) { return ...; }
 public static DeviceClassKey FromActualDevice(ActualDevice ad) { return ...; }

 //add equality members here
}

And now you add members to the set like this:

HashSet<DeviceClassKey> items = ...;
DeviceClass dc = ...;
items.Add(DeviceClassKey.FromDeviceClass(dc));

And you test membership like this:

HashSet<DeviceClassKey> items = ...;
ActualDevice ad = ...;
var isMember = items.Contains(DeviceClassKey.ActualDevice(ad));

I might have missed some requirement of yours but this technique can probably be extended to cover it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top