IDictionary Как получить значение удаленного элемента при удалении [дубликата]

Я хотел бы знать, возможно ли удалить элемент IDictionary по его ключу и одновременно получить его фактическое значение, которое было удалено?

Пример

что-то типа:

Dictionary<string,string> myDic = new Dictionary<string,string>();
myDic["key1"] = "value1";

string removed;
if (nameValues.Remove("key1", out removed)) //No overload for this...
{
    Console.WriteLine($"We have just remove {removed}");
}

Выход

//We have just remove value1

person Shahar Shokrani    schedule 28.08.2018    source источник
comment
Нет, нет. Что происходит, когда ключ не существует?   -  person Ron Beyer    schedule 28.08.2018
comment
@RonBeyer Remove возвращает false, если ключ не существует.   -  person Jonathon Chase    schedule 28.08.2018
comment
@JonathonChase Я это знаю, но что тогда содержит out removed? null? default(T)?   -  person Ron Beyer    schedule 28.08.2018
comment
@RonBeyer Я обновил свой вопрос, мой текущий дизайн в порядке с null.   -  person Shahar Shokrani    schedule 28.08.2018
comment
@RonBeyer Я бы ожидал default(T), как в случае с шаблоном TryXYZ, но вы правы, его нужно определить.   -  person Jonathon Chase    schedule 28.08.2018
comment
Закрытие вопроса с дублирующейся ссылкой. На исходный вопрос есть ответ сегодня (начиная с .NET Core 2.0).   -  person nawfal    schedule 26.07.2020


Ответы (2)


Обычные словари не имеют этой функциональности как атомарной операции, но ConcurrentDictionary<TKey,TValue> TryRemove__0_ConcurrentDictionary<TKey,TValue>_" rel="noreferrer">делает.

ConcurrentDictionary<string,string> myDic = new ConcurrentDictionary<string,string>();
myDic["key1"] = "value1";

string removed;
if (myDic.TryRemove("key1", out removed))
{
    Console.WriteLine($"We have just remove {removed}");
}

Вы можете написать метод расширения для обычного словаря, чтобы реализовать это, но если вы беспокоитесь о том, что он атомарный, ConcurrentDictionary, вероятно, более подходит для вашего варианта использования.

person Marie    schedule 28.08.2018

Вы можете написать метод расширения для этого:

public static class DictionaryExtensions
{
    public static bool TryRemove<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, out TValue value)
    {
        if (dict.TryGetValue(key, out value))
            return dict.Remove(key);
        else
            return false;
    }
}

Это попытается получить значение и, если оно существует, удалит его. В противном случае вы должны использовать ConcurrentDictionary, как сказал другой ответ.

person Ron Beyer    schedule 28.08.2018
comment
Это, безусловно, личное предпочтение, но было бы немного проще следовать, если бы присваивание по умолчанию произошло до возврата false, поскольку это единственный раз, когда оно когда-либо использовалось. - person Marie; 28.08.2018
comment
@RufusL 7.3 может это сделать, в данном случае это не нужно. - person Ron Beyer; 28.08.2018
comment
@RufusL Я тоже собирался спросить об этом. Я удивлен, что пропустил эту функцию, спасибо за внимание! - person Marie; 28.08.2018
comment
@RonBeyer Приятно знать, я думаю, что я все еще немного старой школы .. :) - person Rufus L; 28.08.2018
comment
@RufusL Вы можете установить значение в if и else, потому что охватываются обе возможные ветви. В этом случае вам это вообще не нужно, потому что независимо от того, какое значение присваивается TryGetValue - person Marie; 28.08.2018
comment
Круто, так что все это можно сократить до return dict.TryGetValue(key, out value) && dict.Remove(key); - person Rufus L; 28.08.2018