代码之家  ›  专栏  ›  技术社区  ›  jac

如何使用多个返回类型实现选项

  •  4
  • jac  · 技术社区  · 16 年前


    GetOption(会话超时)
    GetOption(默认客户) 应返回选项实体,且值应为Guid类型。

    5 回复  |  直到 16 年前
        1
  •  2
  •   Brann    16 年前

    有两种解决方案,各有优缺点:

    备选案文1:通用性

    Create table tbGlobalOptions
    (
    OptionName Varchar(255) Identity,
    OptionValue Varchar(255),
    OptionType varchar(255)
    isLocked bit --this indicated the value cannot be overridden by the user. 
    )
    

    和用户选项表:

    Create table tbUserOptions
    (
    OptionName varchar(255)
    UserID bigint,
    OptionValue varchar(255),
    Active bit
    )
    -- extra fields for logging omitted 
    -- keys omitted 
    

    代码包含与OptionName列匹配的枚举,因此需要解析选项 这是微不足道的。

    欺骗:

    • 类型安全只能使用约束或触发器实现(这显然比列类型更难维护)
    • 直接从数据库使用存储的选项比较困难(因为解析逻辑存在于应用程序代码中)

    选项2:专门化(和强类型)

    强类型选项表,每个选项包含一列

    Create table tbOptions
    (
    UserId bigint, -- 0 for global defaults
    Option1 int,
    Option2 varchar(max)
    Option3 int,
    ...
    Option426 bit
    )
    

    类型安全显然是一件好事,但在这里它有巨大的成本:

    • 用于更新表的存储过程将包含大量重复的代码,因为逻辑(例如isLocked机制,或者您可能要添加的一些额外日志记录)必须对每个字段反复进行。这就是存储过程如何包含1500个参数的结果。
    • SQL Server 2008 例如这里)。

    如果您有5种选择,并且这个数字可能会随着时间的推移保持不变,那么第二种解决方案有其优点。

    另一方面,如果你计划最终拥有数千种选择,这对我来说似乎是一个不需要动脑筋的问题:选择泛型!


    在应用程序代码中,使用通用方法可以很容易地解决问题:

    OptionEntity<T> GetOptions<T>(string OptionName, T defaultvalue);
    

    编辑以下内容以回答Bryan的评论:

    是的,如果有10000个值要存储,那么将有10000列。这对于您将要编写的每个表都是正确的。选项表没有什么特别之处。没有什么。

    这一切都取决于我们选择的抽象级别。例如,如何存储棋盘位置?您可以清楚地使用64列表(64个值->(64列) 或者,您可以使用只有4列的设计(游戏id、x、y、内容)。你不认为这两种情况都可以视情况而定吗?

        2
  •  9
  •   Bryan Watts    16 年前

    inner platform effect ,从而尝试通过存储为在数据库中创建数据库 varchar 什么 应该是 不同的、类型化的列。

    您已经为自己提供了在运行时添加选项的能力。但是,如果应用程序不理解它们,它们就没有任何意义,并且您不能在运行时添加这种理解。选项集必须在设计时已知,这意味着模式可以在设计时已知,这意味着您无需将结构抽象为 瓦尔查尔

    抽象实际上并没有给你买任何东西。

    根据OP的评论进行编辑:

    OptionSet 表,每个选项有一列。将只有一行,表示全局集。对于可以由管理器覆盖的每个选项,向 Store 桌子

    然后,您可以有一个方法来询问 商场 要合并有效选项,请执行以下操作:

    public class Store
    {
        public virtual bool? AllowSavePasswords { get; set; }
    
        public virtual OptionSet GetEffectiveOptions(OptionSet globalOptions)
        {
            return new OptionSet
            {
                AllowSavePasswords = this.AllowSavePasswords ?? globalOptions.AllowSavePasswords,
                LoginTimeout = globalOptions.LoginTimeout
    
                // Repeat pattern for all options
            }
        }
    }
    

    如您所见,这允许所有内容都保持强类型,同时解决了无法重写的选项问题。它还表达了哪些选项的意图 可以 商场 表(反映其范围)并使其可为空(反映其可选性质)。

    好的方面是没有新的技术可以学习,也没有“魔法”可以实现(除非你没有看到 ?? operator COALESCE 功能)。

        3
  •  4
  •   STW    16 年前

    您需要的是后期绑定,即在运行时而不是编译时分配变量类型的能力。直接的答案是C#目前不支持这一点,当它得到支持时,它仍然无法完全解决您的问题。

    您最好的选择是使用泛型,这将提高类型安全性,但仍然无法防止愚蠢的错误。创建如下方法:

    public T GetOption<T>(string key)
    {
        // Retrieve the option type and value
        // Check that the option type and return type (T) are compatible
        // cast the option value to T
        // return the value
    }
    

    将允许您尝试将数据库结果强制转换为返回类型T,但如果强制转换失败,它将生成异常(即:您尝试请求GUID选项作为int)。

        4
  •  3
  •   Doc Brown    16 年前

    看看马丁·福勒的书 Analysis Patterns . 福勒称之为“数量”,请看第三章的开头。这基本上是一样的,只需将“数量”替换为“选项”。当然,这只是问题的数据库部分。对于应用程序部分,我建议使用Yooder的解决方案。

        5
  •  2
  •   Brann    16 年前

    在类似的情况下,我经常看到的是提供类型化默认值:

    OptionEntity<T> GetOptions<T>(string OptionName, T defaultvalue);