如何为Hashset制作扩展unionWith

时间:2014-04-12 10:11:50

标签: c# .net linq

我正在尝试为自定义类型进行扩展。这是我的代码。我不知道我的源代码在此代码中是如何变为零的。即使在调试部分hashset temp中也给了我10个logevents的列表。但在决赛中,消息来源变为零。

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

1 个答案:

答案 0 :(得分:0)

这只是默认情况下.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);

...然后foo仍将引用内容为“hello”的字符串。显然你的方法比较复杂,但问题的原因是一样的。

要么你的扩展方法需要修改通过HashSet参数传入的原始source的内容,它应该返回新集。返回新集合更像是习惯性的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会更合适。