何时使用集合与多个属性

时间:2011-06-07 17:22:10

标签: .net class collections properties

我正在为一个ASP.NET应用程序构建一个相对简单的类(例如:Person),该应用程序具有几个相关的布尔属性(例如:Certifications)。我可以选择将它们存储为多个属性:

Class Person
    Property HasCertL1
    Property HasCertL2
    Property HasCertL3
End Class

或使用集合和枚举:

Enum Cert
    L1
    L2
    L3
End Enum

Class Person
    Property Certs as List(Of Cert)
End Class

该类将不会在其他地方使用,并且如果不重新编译该类,则不会更新项目(Certs)。我正在寻找选择其中一个的理由。任何人都可以提供任何最佳实践或指向我可能错过的一些资源吗?提前谢谢!

干杯, JE

4 个答案:

答案 0 :(得分:3)

我的投票是使用一个集合。原因如下:当你为每个级别的认证设置一个属性时,如果你要添加一个级别的认证,你必须添加额外的代码来检查人们是否有这个额外的级别。这可能需要改变使用Person的所有其他类。

如果使用列表,则Person类不会更改;列表的可用值只有一个变化。这需要更少的代码更改来检查特定级别的认证。

答案 1 :(得分:2)

我认为始终关注应用程序的可扩展性是一种很好的方法。考虑到这一点,我会选择收集方法。但是,从您的问题中不清楚是否只有三个认证或是否有更多认证。

您所说的只是通过重新编译来更新认证,在这种情况下听起来有扩展选项。

答案 2 :(得分:1)

为什么你需要一个“集合和枚举”?使用带有“Bit Field”属性的Flags枚举来存储“人物”所具有的“Certs”有什么问题?这实际上只是选项1的一个更清晰的版本。

根据你的评论,这是我正在谈论的一个非常简单的例子:


class Person
{
    public string Name;
    public Certifications Certifications;
}

[Flags]
enum Certifications : int
{
    A = 1,
    B = 2,
    C = 4,
    D = 8,
    E = 16,
    F = 32,
    G = 64,
    H = 128,
    I = 256
};

static void Main()
{
    Person a = new Person() { Name = "rob", Certifications =  Certifications.A | Certifications.D | Certifications.G };
    Person b = new Person() { Name = "jeb", Certifications = Certifications.B | Certifications.C | Certifications.I };

    // Easy way using [Flags] ToString() override.
    DisplayPerson(a);
    DisplayPerson(b);

    Console.WriteLine();

    // Traditional Way
    DisplayPersonInfo( a );
    DisplayPersonInfo( b );
}

static IEnumerable<string> GetCerts( Person person )
{
    foreach( Certifications cert in Enum.GetValues( typeof( Certifications ) ) )
    {
        if( PersonHasCert( person, cert ) )
            yield return ( Enum.GetName( typeof( Certifications ), cert ) );
    }
}

static bool PersonHasCert( Person person, Certifications cert )
{
    return ( ( cert & person.Certifications ) == cert );
}

static void DisplayPersonInfo( Person p )
{
    Console.WriteLine
    (
        String.Format
        (
            "Name: {0}, Certifications: {1}", 
            p.Name, 
            String.Join( ", ", GetCerts( p ) )
        )   
    );
}

static void DisplayPerson(Person p)
{
    Console.WriteLine
    (
        String.Format
        (
            "Name: {0}, Certifications: {1}",
            p.Name,
            p.Certifications
        )
    );
}

输出:

姓名:抢,证明:A,D,G
姓名:jeb,认证:B,C,I

姓名:抢,证明:A,D,G
姓名:jeb,认证:B,C,I

前面提到的“[Flags]”属性有助于编译器知道你正在使用这个数据结构并显示它包含的值(使用带有属性的“Enum”上的ToString()方法,所以你不要当你想要显示所有值时,我必须迭代枚举并对每个值进行逐位测试。)

您对使用此方法有何其他保留意见?它似乎完全适合你想要非常有效和干净地实现的目标。

this是一篇很好的文章,涵盖了这一主题。

编辑2:

示例代码已更新,包括使用两种方式实现此功能的完整示例程序以及您应该能够在应用程序中使用的一些辅助方法。

答案 3 :(得分:1)

我的意见是,这完全取决于你将如何使用这些属性。对于任何用例,通常可以说是将对象作为集合还是作为一组属性更方便。这应该会推动您的选择,尽管将多个属性转换为集合或将集合转换回项目并不困难。

您的情况(您知道自己拥有Cert1Cert2Cert3并且其他任何事情都不是很重要),相比之下,没有人知道收藏品可能有多少项,因此,大多数时候,属性数量有限,不是一种选择。在您的情况下,它可能是一个选项。单独的属性可能允许您以更强类型的方式存储对象。

如果您不知道选择哪个选项,我建议您同时选择这两个选项。实现一个Person类,它将为每个项目提供集合属性和单独属性。内部实现并不重要,只有界面在这里很重要。然后,您将能够使用其他类中的任何内容,并且可能会更清楚地说明应该如何实现它。示例实现(它不能完全实现集合部分,因为您无法向其添加项目):

class Person
{
    public Cert1 Cert1 { get; set; }
    public Cert2 Cert2 { get; set; }
    public Cert3 Cert3 { get; set; }

    public IEnumerable<Cert> AllCertificates
    {
        get
        {
            return new Cert[] {Cert1, Cert2, Cert3}
                        .Where(c => c != null)
                        .ToArray();
        }
    }
}