当前位置:  开发笔记 > 编程语言 > 正文

Lance Hunt的C#编码标准 - 枚举混乱

如何解决《LanceHunt的C#编码标准-枚举混乱》经验,为你挑选了3个好方法。

我的团队最近开始使用Lance Hunt的C#编码标准文档作为巩固我们的编码标准的起点.

有一个项目,我们只是不明白的意义,这里的任何人都可以阐明它吗?

该项目是第77号:

在使用之前始终验证枚举变量或参数值.它们可以包含底层Enum类型(默认int)支持的任何值.

例:

public void Test(BookCategory cat)
{
if (Enum.IsDefined(typeof(BookCategory), cat))
{…}
}

Jon Skeet.. 20

关键是你可能希望通过拥有BookCategory类型的参数,你总是有一个有意义的书类别.情况并非如此.我可以打电话:

BookCategory weirdCategory = (BookCategory) 123456;
Test(weirdCategory);

如果枚举意味着代表一组众所周知的值,则不应期望代码合理地处理该知名集合之外的值.测试首先检查参数是否合适.

我个人反过来说:

public void Test(BookCategory cat)
{
    if (!Enum.IsDefined(typeof(BookCategory), cat))
    {
        throw new ArgumentOutOfRangeException("cat");
    }
}

在C#3中,可以使用扩展方法轻松完成:

// Can't constrain T to be an enum, unfortunately. This will have to do :)
public static void ThrowIfNotDefined(this T value, string name) where T : struct
{
    if (!Enum.IsDefined(typeof(T), value))
    {
        throw new ArgumentOutOfRangeException(name);
    }
}

用法:

public void Test(BookCategory cat)
{
    cat.ThrowIfNotDefined("cat");
}

请参阅http://blogs.msdn.com/brada/archive/2003/11/29/50903.aspx,了解不应使用Enum.IsDefined的原因. (4认同)

仿制药不允许"Enum"/"enum"作为约束,这是一种痛苦...... (2认同)


Marc Gravell.. 17

未检查枚举:

enum Foo { A= 1, B = 2, C = 3}
Foo x = (Foo) 27; // works fine

现在你有一个Foo未定义的.他只是说"检查你的输入".请注意,Enum.IsDefined它相对较慢(基于反射).就个人而言,我倾向于使用带有default抛出异常的开关:

switch(x) {
    case Foo.A: /* do something */ break;
    case Foo.B: /* do something */ break;
    case Foo.C: /* do something */ break;
    default: throw new ArgumentOutOfRangeException("x");
}

可以说,NotSupportedException可能更合适 - 但是哎呀,只要它抛出! (2认同)

同意!抛出新的OldShoeException()比让逻辑失败以及因此出现在其他地方的bug更好. (2认同)


Lance Hunt.. 13

我认为上面的评论几乎都回答了这个问题.基本上,当我写这个规则时,我试图传达一种验证所有输入的防御性编码实践.枚举是一种特殊情况,因为许多开发人员错误地认为它们是经过验证的,而不是.因此,您经常会看到语句或switch语句是否因未定义的枚举值而失败.

请记住,默认情况下,枚举只不过是INT的包装器,并且就像它是一个int一样验证它.

有关正确使用枚举的更详细讨论,您可以查看Brad Abrams和Krzysztof Cwalina的博客文章或他们的优秀书籍"框架设计指南:可重用.NET库的约定,惯用法和模式"



1> Jon Skeet..:

关键是你可能希望通过拥有BookCategory类型的参数,你总是有一个有意义的书类别.情况并非如此.我可以打电话:

BookCategory weirdCategory = (BookCategory) 123456;
Test(weirdCategory);

如果枚举意味着代表一组众所周知的值,则不应期望代码合理地处理该知名集合之外的值.测试首先检查参数是否合适.

我个人反过来说:

public void Test(BookCategory cat)
{
    if (!Enum.IsDefined(typeof(BookCategory), cat))
    {
        throw new ArgumentOutOfRangeException("cat");
    }
}

在C#3中,可以使用扩展方法轻松完成:

// Can't constrain T to be an enum, unfortunately. This will have to do :)
public static void ThrowIfNotDefined(this T value, string name) where T : struct
{
    if (!Enum.IsDefined(typeof(T), value))
    {
        throw new ArgumentOutOfRangeException(name);
    }
}

用法:

public void Test(BookCategory cat)
{
    cat.ThrowIfNotDefined("cat");
}


请参阅http://blogs.msdn.com/brada/archive/2003/11/29/50903.aspx,了解不应使用Enum.IsDefined的原因.
仿制药不允许"Enum"/"enum"作为约束,这是一种痛苦......

2> Marc Gravell..:

未检查枚举:

enum Foo { A= 1, B = 2, C = 3}
Foo x = (Foo) 27; // works fine

现在你有一个Foo未定义的.他只是说"检查你的输入".请注意,Enum.IsDefined它相对较慢(基于反射).就个人而言,我倾向于使用带有default抛出异常的开关:

switch(x) {
    case Foo.A: /* do something */ break;
    case Foo.B: /* do something */ break;
    case Foo.C: /* do something */ break;
    default: throw new ArgumentOutOfRangeException("x");
}


可以说,NotSupportedException可能更合适 - 但是哎呀,只要它抛出!
同意!抛出新的OldShoeException()比让逻辑失败以及因此出现在其他地方的bug更好.

3> Lance Hunt..:

我认为上面的评论几乎都回答了这个问题.基本上,当我写这个规则时,我试图传达一种验证所有输入的防御性编码实践.枚举是一种特殊情况,因为许多开发人员错误地认为它们是经过验证的,而不是.因此,您经常会看到语句或switch语句是否因未定义的枚举值而失败.

请记住,默认情况下,枚举只不过是INT的包装器,并且就像它是一个int一样验证它.

有关正确使用枚举的更详细讨论,您可以查看Brad Abrams和Krzysztof Cwalina的博客文章或他们的优秀书籍"框架设计指南:可重用.NET库的约定,惯用法和模式"

推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有