c#:具有唯一元素的集合

时间:2017-07-10 06:28:08

标签: c# collections hashset

C#中是否有一个集合可以保证我只有独特的元素?我已经读过HashSet,但是这个集合可以包含重复项。这是我的代码:

public class Bean
{
    public string Name { get; set; }

    public int Id { get; set; }

    public override bool Equals(object obj)
    {
        var bean = obj as Bean;

        if (bean == null)
        {
            return false;
        }

        return this.Name.Equals(bean.Name) && this.Id == bean.Id;
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode() * this.Id.GetHashCode();
    }
}

您可能会抱怨在我的GetHashCode方法中使用非只读属性,但这是一种做法(不是正确的)。

        HashSet<Bean> set = new HashSet<Bean>();

        Bean b1 = new Bean {Name = "n", Id = 1};
        Bean b2 = new Bean {Name = "n", Id = 2};
        set.Add(b1);
        set.Add(b2);
        b2.Id = 1;

        var elements = set.ToList();

        var elem1 = elements[0];
        var elem2 = elements[1];

        if (elem1.Equals(elem2))
        {
            Console.WriteLine("elements are equal");
        }

在这种情况下,我的集合包含重复项。

C#中有一个集合可以保证它不包含重复项吗?

2 个答案:

答案 0 :(得分:-1)

  

C#中有一个集合可以保证我没有   包含重复项?

C#中没有现有的集合类可以执行此操作。 您可以编写自己的,但没有现有的。

有关您遇到的问题的一些额外信息

如果在将HashSet条目添加到HashSet后进行更改,则需要重新生成HashSet。我可以使用我RegenerateHashSet以下的内容。

您需要重新生成的原因是重复检测仅发生在插入时(或者换句话说,它依赖于您在插入对象后不更改对象)。如果你考虑一下,这是有道理的。 HashSet无法检测到它包含的对象是否已更改。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
    public static class HashSetExtensions
    {
        public static HashSet<T> RegenerateHashSet<T>(this HashSet<T> original)
        {
            return new HashSet<T>(original, original.Comparer);
        }
    }

    public class Bean
    {
        public string Name { get; set; }

        public int Id { get; set; }

        public override bool Equals(object obj)
        {
            var bean = obj as Bean;

            if (bean == null)
            {
                return false;
            }

            return Name.Equals(bean.Name) && Id == bean.Id;
        }

        public override int GetHashCode()
        {
            return Name.GetHashCode() * Id.GetHashCode();
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            HashSet<Bean> set = new HashSet<Bean>();

            Bean b1 = new Bean { Name = "n", Id = 1 };
            Bean b2 = new Bean { Name = "n", Id = 2 };
            set.Add(b1);
            set.Add(b2);
            b2.Id = 1;

            var elements = set.ToList();

            var elem1 = elements[0];
            var elem2 = elements[1];

            if (elem1.Equals(elem2))
            {
                Console.WriteLine("elements are equal");
            }
            Console.WriteLine(set.Count);
            set = set.RegenerateHashSet();
            Console.WriteLine(set.Count);
            Console.ReadLine();
        }
    }
}

请注意,上述技术不是防弹的 - 如果添加两个重复的对象(对象A和对象B),然后将对象B更改为与对象A不同,则HashSet仍然只有一个条目它(因为从未添加过对象B)。 因此,您可能想要做的事实上是将完整列表存储在列表中,然后在需要唯一条目时使用new HashSet<T>(yourList)如果您决定,以下课程可能会对您有所帮助走那条路。

public class RecalculatingHashSet<T>
{
    private List<T> originalValues = new List<T>();

    public HashSet<T> GetUnique()
    {
        return new HashSet<T>(originalValues);
    }

    public void Add(T item)
    {
        originalValues.Add(item);
    }
}

答案 1 :(得分:-1)

如果您没有编写自己的集合类型并处理属性更改事件以重新评估项目,则需要在每次访问时重新评估项目。这可以通过LINQ延迟执行完成:

items

规则:仅使用reader插入或删除元素,使用Bean b1 = new Bean { Name = "n", Id = 1 }; Bean b2 = new Bean { Name = "n", Id = 2 }; items.Add(b1); items.Add(b2); b2.Id = 1; var elements = reader.ToList(); var elem1 = elements[0]; var elem2 = elements[1]; // throws exception because there is only one element in the result list. 进行任何读取访问。

CREATE TABLE test (id INT NOT NULL PRIMARY KEY IDENTITY(1,1), 
                   text VARCHAR(255)
                  );
GO

CREATE PROCEDURE testProc(@string VARCHAR(255))
AS
BEGIN
    INSERT INTO test (text) VALUES (@string);
    SELECT * FROM test;
END 
GO

EXEC testProc('Test01')