简体   繁体   English

如何为Hashset创建扩展unionWith

[英]How to make extension unionWith for Hashset

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. 即使在调试部分,哈希集的temp也给了我10个logevent的列表。 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. 每当发现重复项时,我都想将其“ filesAndLineNos”与原始项合并。 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. 这只是默认情况下在.NET中按值传递参数的问题。 You're changing the value of source to refer to a different HashSet , and that doesn't change the caller's variable at all. 您正在更改source的值以引用不同的HashSet ,而这根本不会更改调用方的变量。 Assuming that Condense doesn't modify the list (I'm unaware of that method) your method is as pointless as: 假设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();
}

If you call the above with: 如果您通过以下方式致电上述内容:

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

... then foo is still going to refer to a string with contents " hello ". ...然后foo仍将引用内容为“ 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. 无论您的扩展方法需要修改原来的内容HashSet通过传递source参数, 或者它应该返回新集。 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. 返回新集合更像LINQ,但是HashSet.UnionWith 确实会修改原始集合-这取决于您要更接近哪个模型。

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: 但是,请注意:

  • This does not replace the comparer in the existing set. 并不在现有的一组取代比较器。 You can't do that. 你不能那样做。
  • It's pretty inefficient in general. 一般来说,它的效率很低。 It feels like a Dictionary would be a better fit, to be honest. 老实说,这感觉像Dictionary更合适。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM