Set<T> аномалия


13
Разгледах Set-а на PowerCollections, което е общо взето същото като Hashset от .NET Framework. Това са множества имплементирани като хеш-таблици. Ако добавим/изтрием в някоя от колекциите 2 пъти един и същ елемент обаче, не хвърля изключение, както би трябвало според мене, а просто връща True/False дали е успяло. Но не в това е проблемът. Двете колекции се държат различно при добавяне на елемент. Може и аз да греша, ама го гледам това от 10 минути. Някой има ли логично обяснение защо Set-а прави така?
Сорс: http://pastebin.com/ebG04k2K



Отговори



11
Като гледам сорса методът Add вика от своя страна метод Insert на някаква имплементация на хештаблица Hash, която ползват и я вика с параметър replaceOnDuplicate = true , така че ако намери такъв елемент го заменя и връща false този Insert метод , а Add методът пък връща обратното на това което връща Insert метода, така че:
когато добавяш първия път
Insert методът връща true към Add , а Add ти връща на теб false
когато добавяш втория път същия елемент
Insert методът връща false към Add , а Add ти връща на теб true.
Наистина е странно и не мога и аз да измисля точно защо правят тази инверсия на резултата, който се връща от Add методът спрямо Insert-а . Ако я нямаше щеше да връща същото, което и HashSet в .NET връща.
Всъщност в документацията към сорса се вижда, че точно такава им е била целта
///

от mstefanov (761 точки)


0
И аз тъкмо се загледах в реализацията на Add(). Мерси за доп. инфо. Доста неинтуитивно са го направили. Бая време може да ти изяде нещо такова, ако не го знае човек и разчита на true/false. ;)

от Iliev (1241 точки)

0
Така си е :) Особено като си свикнал с логиката на стандартната имплементация заложена в .NET по-различната логика наистина изглежда "нелогична" на пръв поглед. Явно според хората, които са го писали тоя Set в PowerCollections това е "правилната" логика хехе. :)

от mstefanov (761 точки)


0

Не са си проектирали API-то както трябва. Наистина доста неприятна изненада ако избързаш и не прочетеш документацията, мерси че го сподели.

В такива случаи, ако искаш да не се объркаш, можеш да си направиш разширителни методи които да помнят вместо теб:

/// <summary>
/// Adds 'elem' to 'set' and returns 'true' if it was NOT already present.
/// <summary>
/// <returns>
/// 'true' if 'elem' was NOT present in 'set' prior to the insertion.
/// </returns>
public static bool SafeAdd<T>(this Set<T> set, T elem) {
    return !set.Add(elem);
}

/// <summary>
/// Adds 'elem' to 'set' and returns 'true' if it was NOT already present.
/// <summary>
/// <returns>
/// 'true' if 'elem' was NOT present in 'set' prior to the insertion.
/// </returns>
public static bool SafeAdd<T>(this HashSet<T> set, T elem) {
    return set.Add(elem);
}


Така ще можеш и по-лесно да смениш типа на колекцията впоследствие, вместо да се налага да търсиш всички места където ползваш метода.

ПС: как се форматира да го покаже като код в поста?


от staafl (5770 точки)