I am trying to make an extension for the custom type. This is my code. I don't know how my source becomes zero in this code. Even in the debug part hashset temp is giving me a list of 10 logevents. But in the final the source is becoming zero.
public static void UnionSpecialWith(this HashSet<LogEvent> source, List<LogEvent> given,IEqualityComparer<LogEvent> comparer)
{
List<LogEvent> original = new List<LogEvent>(source);
List<LogEvent> second = given.Condense(comparer);
source = new HashSet<LogEvent>(original.Condense(comparer),comparer);
foreach (LogEvent logEvent in second)
{
if (original.Contains(logEvent, comparer))
{
int index = original.FindIndex(x => comparer.Equals(x, logEvent));
original[index].filesAndLineNos.MergeFilesAndLineNos(logEvent.filesAndLineNos);
}
else
original.Add(logEvent);
}
#if DEBUG
String content = String.Join(Environment.NewLine, original.Select(x => x.GetContentAsEventsOnly()));
HashSet<LogEvent> temp = new HashSet<LogEvent>(original, comparer);
#endif
source = new HashSet<LogEvent>(original, comparer);
}
Can anybody point me out what is wrong?
EDIT: This is my custom type. Whenever I found a duplicate , I want to merge it's "filesAndLineNos" with the original one. This is what I am trying to achieve with the above code.
public class LogEvent
{
public String mainEventOriginal;
public String subEventOriginal;
public String mainEvent;
public String subEvent;
public int level;
public Dictionary<String,HashSet<int>> filesAndLineNos;
}
The usage is something like
HashSet<LogEvent> required = new HashSet<LogEvent>(initialUniqueSet);
required.UnionSpecialWith(givenListOfLogEvents);
This is simply a matter of parameters being passed by value in .NET by default. You're changing the value of source
to refer to a different HashSet
, and that doesn't change the caller's variable at all. Assuming that Condense
doesn't modify the list (I'm unaware of that method) your method is as pointless as:
public void TrimString(string text)
{
// This changes the value of the *parameter*, but doesn't affect the original
// *object* (strings are immutable). The caller won't see any effect!
text = text.Trim();
}
If you call the above with:
string foo = " hello ";
TrimString(foo);
... then foo
is still going to refer to a string with contents " hello ". Obviously your method is more complicated, but the cause of the problem is the same.
Either your extension method needs to modify the contents of the original HashSet
passed in via the source
parameter, or it should return the new set. Returning the new set is more idiomatically LINQ-like, but HashSet.UnionWith
does modify the original set - it depends which model you want to be closer to.
EDIT: If you want to modify the set in place, but effectively need to replace the contents entirely due to the logic, then you might want to consider creating the new set, then clearing the old and adding all the contents back in:
public static void UnionSpecialWith(this HashSet<LogEvent> source,
List<LogEvent> given,
IEqualityComparer<LogEvent> comparer)
{
List<LogEvent> original = new List<LogEvent>(source);
List<LogEvent> second = given.Condense(comparer);
foreach (LogEvent logEvent in second)
{
if (original.Contains(logEvent, comparer))
{
int index = original.FindIndex(x => comparer.Equals(x, logEvent));
original[index].filesAndLineNos
.MergeFilesAndLineNos(logEvent.filesAndLineNos);
}
else
{
original.Add(logEvent);
}
}
source.Clear();
foreach (var item in original)
{
source.Add(item);
}
}
However, note:
Dictionary
would be a better fit, to be honest.See more on this question at Stackoverflow