如何在C#中管理多个类? (复制)

时间:2014-05-23 20:29:31

标签: c# visual-studio-2010 class

简单的问题。我正在VS 2010 C#中编写应用程序以获得乐趣(学习体验),我不知道如何以可接受的方式解决问题。

假设我有一个名为“Biscuit”的课程

class Biscuit
{
    private string Brand = String.Empty;
    private string Variant = String.Empty;

    public void CreateBiscuit(string pBrand, string pVariant)
    {
        Brand = pBrand;
        Variant = pVariant;
    }

    public void GetDetails(ref string pBrand, ref string pVariant)
    {
        pBrand = Brand;
        pVariant = Variant;
    }
}

用户可以根据需要创建此对象的任意数量的实例。他们所要做的就是提供品牌和变体。然后我创建对象并将其存储在列表中

问题是,我不希望有重复。所以没有两个对象,其中Brand和Variant都与另一个实例相同。

我可以遍历BiscuitLibrary中的所有对象,但这似乎不是好的练习,也不是很好的表现。 (下面的当前代码)

    List<Biscuit> BiscuitLibrary = new List<Biscuit>();

    public void CheckDuplicate(string pBrand, string pVariant)
    {
        string ObjectBrand = String.Empty
        string ObjectVariant = String.Empty;

        foreach (Biscuit CurrentItem in BiscuitLibrary)
        {
            CurrentItem.GetDetails(ref ObjectBrand, ref ObjectVariant);

            if ((ObjectBrand == pBrand) && (ObjectVariant == pVariant))
            {
                MessageBox.Show("This Biscuit Already Exists, Sorry!");
            }
            else
            {
                Biscuit NewBiscuit = new Biscuit();

                NewBiscuit.CreateBiscuit(pBrand, pVariant);

                BiscuitLibrary.Add(NewBiscuit);
            }

        }
    }

我该怎么做?

谢谢,汤姆!

3 个答案:

答案 0 :(得分:1)

最佳做法可能是将所有实例存储在HashSet而不是List中。如果您计划存储数千个实例,这对性能尤其有用。在列表中查看每个列表并检查重复项将是一项昂贵的操作。 HashSet以允许非常有效的重复检查的方式基于对象哈希码组织其内容。您可以在此处阅读有关HashSet的更多信息: http://msdn.microsoft.com/en-us/library/bb397727(v=vs.110).aspx

在使用HashSet之前,您必须通过重写其GetHashCode()和Equals()方法来准备您的类:

class Biscuit
{
    public string Brand { get; set; }
    public string Variant { get; set; }

    public Biscuit(string brand, string variant)
    {
        Brand = brand;
        Variant = variant;
    }

    public override bool Equals(object obj)
    {
        if (obj == null || typeof(Biscuit) != obj.GetType())
            return false;

        Biscuit biscuitObj = obj as Biscuit;

        return biscuitObj.Brand == this.Brand && biscuitObj.Variant == this.Variant;
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + this.Brand.GetHashCode();
            hash = hash * 23 + this.Variant.GetHashCode();
            return hash;
        }
    }   
}

现在您可以将此类与HashSet一起使用:

//we create a HashSet and add 4 biscuits to it
//one of the biscuits is duplicate and will not be inserted
var uniqueBiscuitBox = new HashSet<Bisquit>();
uniqueBiscuitBox.Add(new Biscuit("A", "1"));
uniqueBiscuitBox.Add(new Biscuit("A", "1"));
uniqueBiscuitBox.Add(new Biscuit("B", "1"));
uniqueBiscuitBox.Add(new Biscuit("C", "4"));
Console.WriteLine(uniqueBiscuitBox.Count()); //returns 3

答案 1 :(得分:0)

由于您已经使用类似于Factory模式的东西,您可以对代码进行一些修改,使其按照您的意愿运行:

class Biscuit
{
    // You should use properties
    public string Brand {get; private set;}
    public string Variant {get; private set;}

    // Use a protected constructor so it can't be used outside the class
    protected Biscuit(string brand, string variant)
    {
        Brand = brand;
        Variant = variant;
    }

    // Use a static list to hold the already crated biscuits
    private static List<Biscuit> _existingBiscuits = new List<Biscuit>();

    // "Factory method" to create Biscuit instances
    public static Biscuit CreateBiscuit(string pBrand, string pVariant)
    {
        // Use LINQ to find if there are any biscuits already crated with the brand and variant 
        if (_existingBiscuits.Any(b => b.Brand == pBrand && b.Variant == pVariant))
        {
            // If the biscuit already exist return null, no biscuit created
            return null;
        }
        else
        {
            // Create biscuit and add it to the list
            var biscuit = new Biscuit(pBrand, pVariant);
            _existingBiscuits.Add(biscuit);

            return biscuit; 
        }       
    }
}

答案 2 :(得分:0)

第一个建议:要求实例用有效数据构建;如果用户尝试传递无效数据并且避免“构造然后初始化”反模式,则抛出。

public class Biscuit : IEquatable<Biscuit>
{
    public string Brand { get; private set; }
    public string Variant { get; private set; }

    public Biscuit(string brand, string variant)
    {
        if (brand == null) throw new ArgumentNullException("brand");
        if (variant == null) throw new ArgumentNullException("variant");
        Brand = brand;
        Variant = variant;
    }

    public bool Equals(Biscuit b)
    {
        if (b == null) return false;
        return string.Equals(Brand, b.Brand, StringComparison.InvariantCulture)
               && string.Equals(Variant, b.Variant, StringComparison.InvariantCulture);
    }
}

如果您想要一个包含特殊规则的列表(例如,没有两个项目具有相同的Brand和Variant),则创建一个实现规则的类。不要使用通用列表并尝试在运行时强制执行规则。

复制@ SoftwareFactor的想法,您可以使用HashSet创建强类型IEqualityComparer

class BiscuitEqualityComparer : IEqualityComparer<Biscuit>
{
    public bool Equals(Biscuit b1, Biscuit b2)
    {
        if (b1 == null) return b2 == null;
        return b1.Equals(b2);
    }

    public int GetHashCode(Biscuit b)
    {
        if (b == null) throw new ArgumentNullException("b");
        return b.Brand.GetHashCode() ^ b.Variant.GetHashCode();
    }
}


var bh = new HashSet<Biscuit>(new BiscuitEqualityComparer());
bh.Add(new Biscuit("Alpha", "Beta"));
bh.Add(new Biscuit("Alpha", "Gamma"));
bh.Add(new Biscuit("Alpha", "Beta"));    // will not be added.