代码之家  ›  专栏  ›  技术社区  ›  James Black

确定变量类型并在f中对每个变量进行不同处理的最佳方法#

  •  1
  • James Black  · 技术社区  · 14 年前

    我有一个函数可以创建一个select-where子句,但现在所有内容都必须是一个字符串。

    我想看看传入的变量,确定它是什么类型,然后正确地处理它。

    例如,数值周围没有单引号,选项类型要么为空,要么有一些值,布尔值实际上是零或一。

    member self.BuildSelectWhereQuery (oldUser:'a)  =  //'
        let properties = List.zip oldUser.ToSqlValuesList sqlColumnList 
        let init = false, new StringBuilder()
        let anyChange, (formatted:StringBuilder) = 
            properties |> Seq.fold (fun (anyChange, sb) (oldVal, name) ->
                match(anyChange) with
                | true -> true, sb.AppendFormat(" AND {0} = '{1}'", name, oldVal)
                | _ -> true, sb.AppendFormat("{0} = '{1}'", name, oldVal)
            ) init
        formatted.ToString()
    

    这里有一个实体:

    type CityType() =
        inherit BaseType()
        let mutable name = ""
        let mutable stateId = 0
        member this.Name with get() = name and set restnameval=name <- restnameval
        member this.StateId with get() = stateId and set stateidval=stateId <- stateidval
        override this.ToSqlValuesList = [this.Name; this.StateId.ToString()]
    

    所以,如果 name 是除了字符串之外的其他值,或者 stateId 可以是可选的,然后我要做两个更改:

    1. 如何将TosqlValuesList修改为 有变量,这样我就可以知道 变量类型?
    2. 如何更改选择功能 处理这个问题?

    我想我需要一个新的函数来进行处理,但是最好的fp方法是什么,而不是使用 typeof ?

    2 回复  |  直到 14 年前
        1
  •  2
  •   Tomas Petricek    14 年前

    我认为一种明确的功能性方法是定义一种数据类型,它表示您需要处理的各种(更复杂的情况)。您提到一个值可能是可选的,并且您需要区分数值和文本值(对于SQL编码)。

    您可以定义一个有区别的联合(如果您希望处理其他情况,则定义可能会更复杂一些):

    type SqlValue = 
      | Missing
      | Numeric of string
      | Textual of string
    

    请注意 Textual 箱子也带有 string ,因为我假设生成该值的客户机负责将其转换为字符串—这只是您的SQL查询生成器的信息(以便它知道是否需要添加引号)。

    你的 ToSqlValuesList 成员将返回值列表 string & SqlValue 例如,可以使用以下列表表示示例产品:

    columns = [ "Name"; "Price"; "Description" ]
    values = [ Textual("Tea"); Numeric(10); Missing ]
    

    在生成SQL查询的代码中,您将使用模式匹配来处理所有不同的情况(最重要的是,如果值为 文本的 -)

    编辑 您需要实现从特定数据类型到 SqlValue 代表每个客户。但是,可以通过编写实用程序类型(使用可以重载成员的事实)来简化这一过程:

    type SqlValue with 
      static member From(a:int) = Numeric(a.ToString())
      static member From(a:int option) = 
        match a with None -> Missing | Some(n) -> SqlValue.From(n)
      // ... similarly for other types
    

    在执行 列值列表 ,你会写 SqlValue.From(description) 它会自动处理细节。

    更复杂的方法是用.NET属性注释表示数据实体的类型的公共成员,并使用反射在运行时提取值(及其类型)。这是更先进的,但相当优雅(这是一个很好的例子,在唐赛姆的专家F书)

        2
  •  3
  •   Jason    14 年前

    您可以在匹配中使用类型测试模式。这能满足你的需要吗?

    let f (x : obj) =
        match x with
        | :? int -> "int"
        | :? string -> "string"
        | :? bool -> "bool"
        | _ -> "who knows?"