【问题标题】:.Net - Strategies to avoid magic string.Net - 避免魔法字符串的策略
【发布时间】:2010-07-08 15:57:59
【问题描述】:

在工作代码中,我们有很多魔术字符串的用法,比如下面的代码 sn-p:

if (user.HasRight("Profile.View")) {...}

所以有很多地方我们传递一个字符串作为参数来查看用户是否有特定的权限。我不喜欢这样,因为这会产生很多魔术字符串。

有什么更好的方法?

枚举、常量、类?

【问题讨论】:

    标签: .net magic-string


    【解决方案1】:

    在这种特定情况下,请使用枚举。不会有魔术字符串,如果 Enum 发生变化(以一种会破坏魔术字符串解决方案的方式),应用程序将不再编译。

    public enum ProfilePermissions
    {
        View,
        Create,
        Edit,
        Delete
    }
    

    那么你可以简单地拥有:

    if(user.HasRight(ProfilePermissions.View)) { }
    

    你也可以使用一个类,但是当涉及到更复杂的场景时你会限制自己。例如,将枚举简单更改为:

    public enum ProfilePermissions
    {
        View = 1,
        Create = 2,
        Edit = 4,
        Delete = 8
    }
    

    将允许您对更复杂的权限使用按位运算符(例如,用户需要创建或删除的情况):

    if(user.HasRight(ProfilePermissions.Create | ProfilePermissions.Delete));
    

    【讨论】:

    • 根据要求,这也可以转换为标志枚举,即可以使用 | 组合值,例如使用值 0x1、0x2、0x4 等...
    • 很好的答案,我的答案是相同的。我可能会补充一点,enum 的目的是创建一个常量的“枚举列表”。将常量分组到可以像这样列出的位置是一个好主意,也可以让程序更有逻辑性。
    • 如果还需要字符串表示,例如要以人类可读的方式存储权限集,您可以简单地调用 ProfilePermissions.View.ToString() 来获取字符串“View”,或者如果您需要自定义字符串表示,您可以添加一个装饰 Description此处描述的属性:blogs.msdn.com/b/abhinaba/archive/2005/10/20/483000.aspx
    • 当您需要添加权限时会发生什么?重新编译?常量和枚举应该用于静态数据。查看、创建、编辑和删除都可以,但我不会调用枚举 ProfilePermissions,只调用 Permissions。在配置文件类中添加权限属性,您就完成了。整个事情可以在外部数据源中进行管理,并且您的代码保持其可读性和安全性。
    • 我是枚举替换魔术字符串的忠实粉丝。另一个不错的功能是您绝对必须传入一个字符串(比如说因为它是一个只处理字符串的第三方库),您可以使用 ToString() 方法来保持使用枚举的强度,但仍然有一个字符串。它仅适用于字母字符,但很方便。例如 ThirdPartyLibrary.GetResponse(string role) 可以将 enum Roles { Admin, Editor, Guest } 作为 ThirdPartyLibrary.GetResponse(Roles.Guest.ToString()) 代码>
    【解决方案2】:

    这在 .NET 框架中也很常见。例如 System.Windows.DataFormats 和 System.Net.WebRequestMethods.Http。你想要只读的品种:

    public static class MumbleRights {
      public static readonly string ProfileView = "Profile.View";
      // etc..
    }
    

    【讨论】:

    • @Markus,如果从外部程序集中使用公共常量,它们会被烘焙;如果您稍后更改公共常量,外部程序集仍将使用它在编译时看到的常量。
    • 是的,世界上很少有常量足够不变,可以成为公共常量。 Math.Pi 没问题。
    【解决方案3】:

    扩展方法!将它们放在同一个地方以跟踪所有魔术字符串。

    public static class UserRightsExtensions {
      public static bool CanReadProfile(this User user)
      {
        return user.HasRight("Profile.View");
      }
    
      // etc..
    }
    

    那么你可以:

    if (user.CanReadProfile()) .....
    

    【讨论】:

      【解决方案4】:

      创建一个对这些属性进行强类型化的类,例如

      public static class UserInfo
      {
        public static bool CanViewProfile { get { return User.HasRight("Profile.View"); } }
      }
      

      这会将您的“魔术字符串”保留在代码中的一个位置。枚举也可以,但在我看来它不那么可读。

      注意:我的示例旨在充当登录用户的属性代理,因此是静态类。如果您想要一些可以处理更直接的数据(例如,用户列表)的东西,那么这种类型的类需要是非静态的,并且需要在每个用户帐户的基础上进行实例化。

      【讨论】:

      • CanViewProfile 在我看来作为静态属性毫无意义,而应该是用户对象上的实例方法。 sn-p 建议每个用户都有一个静态类?
      • 不,我不是建议为每个用户使用一个静态类。上面的类只是作为登录用户属性的代理。 (我使用“Alice”是因为我习惯使用 alice、bob、charlie、david 等来代替 foo/bar。
      【解决方案5】:

      你可以在 C# 中做常量字符串。

      您可以像这样在标头中定义所有字符串:

      const string PROFILE_VIEW "Profile.View";
      

      不确定这是否是“最佳”方式,但它肯定比在代码中使用魔法值更好。

      【讨论】:

        【解决方案6】:

        我赞同“贾斯汀·尼斯纳”所展示的方式。但在某些情况下,我宁愿编写以下代码结构。

        public  class User
            {
                public Permission Permission { get; set; }
        
            }
            public abstract class Permission
            {
        
            }
            public class ViewPermission:Permission
            {
        
            }
        

        你可以把它当作

        User user=new User();
                    if(user.Permission is ViewPermission)
                    {
        
                    }
        

        【讨论】:

          猜你喜欢
          • 2012-06-21
          • 2011-08-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多