如何使Hashset的扩展名unionWith



我正在尝试为自定义类型进行扩展。这是我的密码。我不知道我的源代码在这段代码中是如何变成零的。即使在调试部分,hashsettemp也给了我一个10个日志事件的列表。但最终,来源变成了零。

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);
}

有人能告诉我出了什么问题吗?

编辑:这是我的自定义类型。每当我发现一个重复的,我想把它的"filesAndLineNos"和原来的合并。这就是我试图通过上面的代码来实现的。

public class LogEvent 
{
    public String mainEventOriginal;
    public String subEventOriginal;
    public String mainEvent;
    public String subEvent;
    public int level;
    public Dictionary<String,HashSet<int>> filesAndLineNos;
}

用法有点像

HashSet<LogEvent> required = new HashSet<LogEvent>(initialUniqueSet);
required.UnionSpecialWith(givenListOfLogEvents);

这只是默认情况下.NET中按值传递参数的问题。您正在更改source的值以引用不同的HashSet,这根本不会更改调用者的变量。假设Condense不修改列表(我不知道这个方法),那么你的方法就像一样毫无意义

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();
}

如果你用打电话给上面的人

string foo = "   hello   ";
TrimString(foo);

则CCD_ 4仍将引用内容为"hello"的字符串。显然,你的方法更复杂,但问题的原因是一样的。

您的扩展方法需要修改通过source参数传入的原始HashSet的内容,或者它应该返回新的集合。返回新集合更像LINQ,但HashSet.UnionWith确实修改了原始集合-这取决于您想要更接近哪个模型。

编辑:如果您想在适当的位置修改集合,但由于逻辑原因,实际上需要完全替换内容,那么您可能需要考虑创建新集合,然后清除旧集合并将所有内容添加回:

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); 
    }
}

但是,请注意:

  • 这不会替换现有集合中的比较器。你不能那样做
  • 总的来说效率很低。老实说,感觉Dictionary更适合

相关内容

  • 没有找到相关文章

最新更新