1

我在这里看到了有关如何制作每个键具有多个值的字典的帖子,例如此链接中提供的解决方案之一:

多值字典

看来我必须使用 List<> 作为键的值,以便一个键可以存储多个值。

如果您想添加值,链接中的解决方案很好。但我现在的问题是如何从单个键中删除特定值。

我有这段代码用于向字典添加值:

private Dictionary<TKey, List<TValue>> mEventDict;
    // this is for initializing the dictionary


public void Subscribe(eVtEvtId inEvent, VtEvtDelegate inCallbackMethod)
    {
        if (mEventDict.ContainsKey(inEvent))
        {
            mEventDict[inEvent].Add(inCallbackMethod);
        }
        else
        {
            mEventDict.Add(inEvent, new List<TValue>() { v });
        }
    }
// this is for adding values to the dictionary.
// if the "key" (inEvent) is not yet present in the dictionary,
// the key will be added first before the value

我现在的问题是从键中删除特定值。我有这个代码:

public void Unsubscribe(eVtEvtId inEvent, VtEvtDelegate inCallbackMethod)
    {
        try
        {
            mEventDict[inEvent].Remove(inCallbackMethod);
        }

        catch (ArgumentNullException)
        {
            MessageBox.Show("The event is not yet present in the dictionary");
        }
    }

基本上,我所做的只是将 Add() 替换为 Remove() 。这行得通吗?

此外,如果您对代码有任何问题或疑问(初始化等),请随时提出。

感谢您的建议。

4

3 回答 3

2

TylerOhlsen 的回答是朝着正确方向迈出的一步,但它有 6 个键查找(调用 Remove、ContainsKey 和索引器)。使用 TryGetValue 可以将其减少到三个:

private Dictionary<TKey, List<TValue>> mEventDict;

public void Subscribe(TKey inEvent, TValue inCallbackMethod)
{
    List<TValue> list;

    if (mEventDict.TryGetValue(inEvent, out list))
        list.Add(inCallbackMethod);
    else
        mEventDict.Add(inEvent, new List<TValue> { inCallbackMethod });
}

public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
    List<TValue> list;

    if (!mEventDict.TryGetValue(inEvent, out list))
        return false;

    bool removed = list.Remove(inCallbackMethod);

    if (list.Count == 0)
        mEventDict.Remove(inEvent);

    return removed;
}

如果您不关心删除空列表:

public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
    List<TValue> list;

    if (!mEventDict.TryGetValue(inEvent, out list))
        return false;

    return list.Remove(inCallbackMethod);
}

如果您不需要报告该项目是否在列表中(因此从列表中删除),请将返回类型更改为 void,并且(在第一个版本中)删除该removed变量。

于 2012-10-17T05:09:54.547 回答
1

它会起作用吗?不完全是你想要的方式......

  • 您的方法参数需要是泛型类型。
  • List(T).Remove 不会引发 ArgumentNullException。
  • 如果您的列表为空,您可能需要清理您的字典。
  • 调用者可能不关心回调是否在他们取消订阅时被订阅,但您拥有该信息,因此您不妨返回它。此信息可能有助于故障排除/记录目的。

这就是我要推荐的...

private Dictionary<TKey, List<TValue>> mEventDict;

public void Subscribe(TKey inEvent, TValue inCallbackMethod)
{
    if (!mEventDict.ContainsKey(inEvent))
        mEventDict.Add(inEvent, new List<TValue>());

    mEventDict[inEvent].Add(inCallbackMethod);
}

public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
    if (!mEventDict.ContainsKey(inEvent))
        return false;

    bool removed = mEventDict[inEvent].Remove(inCallbackMethod);

    if (mEventDict[inEvent].Count == 0)
        mEventDict.Remove(inEvent);

    return removed;
}

注意:我没有测试过这段代码,所以试试吧。此外,此代码不是线程安全的。

于 2012-10-17T04:01:09.393 回答
0

@phoog - 所以我想将 Unsubscribe 方法保留为void. 修改代码后,这就是我想出的......

public void Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
    List<TValue> list;

    bool mRemoved = false.

    if (mEventDict.TryGetValue(inEvent, out list))
    {
        list.Remove(inCallbackMethod);
        mRemoved = true;
    }
}

listRemoved变量是必要的吗?但是话又说回来,我认为如果inCallbackMethod无法在列表中找到,什么都不会发生。

于 2012-10-17T22:59:15.500 回答