Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>А вообще, вот такое поведение, где operator[] создаёт default в случае отсутствия — очень удобно.
Согласен. Реально удобно для словарей, в которые постоянно складываются данные.
Проблема в том, код в дотнете заточен под политику "все потенциально проблемные действия должны быть оформлены явно".
Добавление элемента в словарь при получении значения очень неочевидно и может выстрелить самым внеапным способом. Например, сценарий "один раз заполнили — потом возвращаем что есть": в теории словарь readonly, по факту — незаметно заполняется "мусорными" ключами.
В общем, с точки зрения оф.гадлайнов для дотнета, такая штука должна предлагаться как приятное дополнение а не быть включённой в дефолтный контейнер
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>А вообще, вот такое поведение, где operator[] создаёт default в случае отсутствия — очень удобно. Потому что обычно default является нейтральным элементом относительно применяемых операций. Простой пример это подсчёт количества вхождений — ++count[id], или например конкатенация строк result_string[id] += s;, или случай ТС со вложенными контейнерами.
Дефолтное значение это обычно null=) И далеко не каждый класс имеет дефолтный конструктор. Имхо лучше не надо такое добавлять.
Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>Это понятно. В STL есть отдельный метод find который не создаёт ничего, а только ищет. EP>А вообще, вот такое поведение, где operator[] создаёт default в случае отсутствия — очень удобно. Потому что обычно default является нейтральным элементом относительно применяемых операций. Простой пример это подсчёт количества вхождений — ++count[id], или например конкатенация строк result_string[id] += s;, или случай ТС со вложенными контейнерами.
А для классов default(T) будет null. И не всегда нужен 0 по умолчанию для чисел.
По уму нужно передавать в конструктор словаря конструктор значения по умолчанию.
Тогда
d.GetOrAdd(ключ) будет возвращать значение по умолчанию. И логика понятна.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, agat50, Вы писали:
EP>>А вообще, вот такое поведение, где operator[] создаёт default в случае отсутствия — очень удобно. Потому что обычно default является нейтральным элементом относительно применяемых операций. Простой пример это подсчёт количества вхождений — ++count[id], или например конкатенация строк result_string[id] += s;, или случай ТС со вложенными контейнерами. A>Дефолтное значение это обычно null=)
Это только при pointer/reference-semantics. У value-типов, превалирующих в C++, обычно есть вполне конкретный дефолт-конструктор, и это очень удобно.
A>И далеко не каждый класс имеет дефолтный конструктор.
Без проблем. Нет дефолтного конструктора — метод нельзя использовать, он не работает — ошибка компиляции. Если есть — то можно.
Здравствуйте, Serginio1, Вы писали:
S>По уму нужно передавать в конструктор словаря конструктор значения по умолчанию. S>Тогда S> d.GetOrAdd(ключ) будет возвращать значение по умолчанию. И логика понятна.
Либо тип-wrapper, у которого будет другой конструктор — так не будет оверхеда на хранение значения.
Либо просто отдельная функция как уже выше предлагали, а-ля get_or_default(map, key, default).
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Serginio1, Вы писали:
S>>По уму нужно передавать в конструктор словаря конструктор значения по умолчанию. S>>Тогда S>> d.GetOrAdd(ключ) будет возвращать значение по умолчанию. И логика понятна.
EP>Либо тип-wrapper, у которого будет другой конструктор — так не будет оверхеда на хранение значения. EP>Либо просто отдельная функция как уже выше предлагали, а-ля get_or_default(map, key, default).
Так есть же GetOrAdd Method в разных вариациях
Вот простейший
public TValue GetOrAdd(
TKey key,
Func<TKey, TValue> valueFactory
)
А с дефаултным конструктором значения код будет значительно короче, так как конструктор значения в основном всегда одинаков
То есть
Но по большому разница то не велика, если определить Func<TKey, TValue> как переменную
d.GetOrAdd(ключ)
d.GetOrAdd(ключ,Конструктор)
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, _NN_, Вы писали:
_NN>Использование простого Dictionary не очень удобно, т.к. добавление или изменение требует нескольких TryGetValue и Add в случае если нет элементов.
Если я правильно понял, весь сыр-бор из-за того, что какой-то умник решил вместо удобного "дефолтового значения" сыпать исключения при отсутствии ключа. В Перле (за 20 лет практического применения!) ни один не пожаловался, что есть дефолтовая величина. Отсюда простой вывод — гнать в шею этих танцоров-архитекторов и внедрять нормальный словарь.
X>Далее, если нужно, мульти-словарь процесс-потоки итэдэ. Это уже делается довольно просто всего лишь несколькими методами расширения.
Это как вариант конечно.
Подумываю об этом.
X>Если рассуждать об абстрактной задаче, то X>
Здравствуйте, Ромашка, Вы писали:
Р>Здравствуйте, _NN_, Вы писали: _NN>>Dictionary и есть хештаблица. _NN>>Или я чего-то не понимаю ?
Р>Ну да. Так и посчитайте один хеш из всех своих параметров и храните в одном dictionary без вложенности.
А удобство пользования ?
Вместо d[x][y] писать d.Where(_ => _.X == x && _.Y == y).First() ?
Удалить вместо простого Remove придется писать намного больше кода.
Здравствуйте, Sinix, Вы писали:
_NN>>И все это вместо простых чисел ? S>Разумеется. Потому что твоя гипотетическая простота на практике оборачивается усложнением. Вместо удобной объектной модели ты в одной коллекции хранишь кишки каждого из элементов. Мало того, что это неудобно (легко забыть и перепутать порядок ключей), так ещё и сыпется на простейших задачах вида "добавить имя к процессу".
Осталось написать код для MyCollection и перейти на C# 6
Здравствуйте, _NN_, Вы писали: _NN>А удобство пользования ?
Блин, хеш подсчитать, не новые объекты составлять. Вот тебе простейший со стрингом (не делай так, придумай какой-нибудь более приятный алгоритм)
public class MyCoolDictionary<T>
where T : new()
{
private Dictionary<string, T> _internalDictionary = new Dictionary<string, T>();
public T this[object x, params object[] others]
{
get
{
var hash = this.GetHash(x, others);
if (!_internalDictionary.ContainsKey(hash))
_internalDictionary.Add(hash, new T());
return _internalDictionary[hash];
}
}
private string GetHash(object x, params object[] others)
{
var str = new StringBuilder();
str.Append(x.GetHashCode());
foreach (var obj in others)
str.Append(obj.GetHashCode());
return str.ToString();
}
}
_NN>Вместо d[x][y] писать d.Where(_ => _.X == x && _.Y == y).First() ?
d[x, y, z /*...*/]
Всё, что нас не убивает, ещё горько об этом пожалеет.
Здравствуйте, Ромашка, Вы писали:
Р>Здравствуйте, _NN_, Вы писали: _NN>>А удобство пользования ?
Р>Блин, хеш подсчитать, не новые объекты составлять. Вот тебе простейший со стрингом (не делай так, придумай какой-нибудь более приятный алгоритм)
Об этом я изначально и говорил, создать специализированные словари для множественных вложений.
Я тут вижу простой список объектов Data. Если будет достаточно простым перебором списка найти нужный объект, то городить огород с вложенными словарями не требуется. Добавь в Data идентификаторы для процессов, потоков, окон, да и всё.
Вместо двух словарей проще использовать один с составным ключом. Редко пеишу на C# но что типа такого
public struct MyStruct<X,Y>
{
public X СвойствоX;
public Y СвойствоY;
public MyStruct(X СвойствоX, Y СвойствоY)
{
this.СвойствоX = СвойствоX;
this.СвойствоY = СвойствоY;
}
public override int GetHashCode()
{
//Упростим задачу и сделаем по простомуstring str= Convert.ToBase64String(BitConverter.GetBytes(СвойствоX.GetHashCode()))+ Convert.ToBase64String(BitConverter.GetBytes(СвойствоY.GetHashCode()));
return str.GetHashCode();
}
//Можно взять из Tuple
//internal static int CombineHashCodes(int h1, int h2)
//{
// return (h1 << 5) + h1 ^ h2;
//}public override bool Equals(object obj)
{
if (obj.GetType()!= GetType()) return false;
var Объект = (MyStruct<X, Y>)obj;
return СвойствоX.Equals(Объект.СвойствоX) && СвойствоY.Equals(Объект.СвойствоY);
}
}
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, Ромашка, Вы писали:
Р>>Здравствуйте, _NN_, Вы писали: _NN>>>Dictionary и есть хештаблица. _NN>>>Или я чего-то не понимаю ?
Р>>Ну да. Так и посчитайте один хеш из всех своих параметров и храните в одном dictionary без вложенности.
_NN>А удобство пользования ? _NN>Вместо d[x][y] писать d.Where(_ => _.X == x && _.Y == y).First() ? _NN>Удалить вместо простого Remove придется писать намного больше кода.
Не намного пройтись по ключам и найти Ключи по X. Всего 2 строчки
var ключи=d.Keys.Where(key=> key.Item1==x).Select(key=> key).ToList();
foreach (var ключ in ключи) d.Remove(ключ );
Здравствуйте, Serginio1, Вы писали:
S> Либо сделать наследника от Dictionary и использовать конструктор значения по умолчанию S>http://rsdn.ru/forum/dotnet/6218191.1
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, Serginio1, Вы писали:
S>> Либо сделать наследника от Dictionary и использовать конструктор значения по умолчанию S>>http://rsdn.ru/forum/dotnet/6218191.1
_NN>Либо специализированный класс и всё еще проще: _NN>
_NN>d.RemoveByFirst(x)
_NN>d[x,y]
_NN>
Наследник проще в том, что нужно добавить всего несколько методов, но используя методы словаря плюс расширения.
специализированный класс я так понимаю будет врапером?
Хотя конечно можно все сгенерить по метаданным например T4.
А можно взять исходники и переделать под себя.
и солнце б утром не вставало, когда бы не было меня