Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在F#中是否有一种方法可以针对泛型类型进行类型测试而不指定实例类型?_F# - Fatal编程技术网

在F#中是否有一种方法可以针对泛型类型进行类型测试而不指定实例类型?

在F#中是否有一种方法可以针对泛型类型进行类型测试而不指定实例类型?,f#,F#,我正在尝试与我关心的几个SQL生成类型进行模式匹配。理想情况下,我想这样做: let rec getSafeValue record (prop: PropertyInfo) = match prop.GetValue(record, null) with | :? string as str -> "'" + str + "'" | :? Option<_> as opt -> match opt with |

我正在尝试与我关心的几个SQL生成类型进行模式匹配。理想情况下,我想这样做:

let rec getSafeValue record (prop: PropertyInfo) = 
    match prop.GetValue(record, null) with
    | :? string as str -> "'" + str + "'"
    | :? Option<_> as opt -> 
        match opt with
        | Some v -> getSafeValue v prop
        | None -> "null"
    | _ as v -> v.ToString()
let rec getSafeValue记录(prop:PropertyInfo)=
将prop.GetValue(记录,null)与
| :? 字符串形式为str->“'”+str+“”
| :? 选项为opt->
匹配
|一些v->getSafeValue v道具
|无->“空”
|_uu作为v->v.ToString()
问题在于,这里,
选项
的类型参数获得了与
记录
的类型参数匹配的约束,该约束最终只是
obj

我知道我可以在基于反射的检查(检查它是否是泛型类型,以及它是否是基于名称的选项类型)中做一些工作,但如果可能的话,我宁愿避免这种情况。

如果没有协方差,这在F#中是行不通的。假设您很高兴
v
属于
obj
类型,您希望能够将
选项
视为
选项
。没有协方差,
Option
Option
是独立的类型。

当我把你的代码放在F#Interactive中时,它似乎使“record”成为一个通用参数。也许它在普通编译器中的工作方式不同。无论如何,由于
GetValue
的第一个参数是type
obj
,它可能正在拾取
obj
类型

很抱歉,我现在不能测试这个,但是试一试。
函数使用一个通用参数,因此这可能会起作用

let rec getSafeValue record (prop: PropertyInfo) = 
    match prop.GetValue(box record, null) with
    | :? string as str -> "'" + str + "'"
    | :? Option<_> as opt -> 
        match opt with
        | Some v -> getSafeValue v prop
        | None -> "null"
    | _ as v -> v.ToString()
let rec getSafeValue记录(prop:PropertyInfo)=
将prop.GetValue(框记录,null)与
| :? 字符串形式为str->“'”+str+“”
| :? 选项为opt->
匹配
|一些v->getSafeValue v道具
|无->“空”
|_uu作为v->v.ToString()

某些v->getSafeValue v道具只有在v与记录的类型相同时才起作用。(或从该类型派生)否则第一行将失败。除非prop指向的属性在第一个参数的上下文中有意义(aka是类型的一部分),否则不能说prop.GetValue(record,null)

如果是同一类型,您可以执行以下操作:

let rec getSafeValue (record:'a) (prop: PropertyInfo) = 
    match prop.GetValue(box record, null) with
    | :? string as str -> "'" + str + "'"
    | :? Option<'a> as opt -> 
        match opt with
        | Some v -> getSafeValue v prop
        | None -> "null"
    | _ as v -> v.ToString()
let rec getSafeValue(记录:'a)(属性:PropertyInfo)=
将prop.GetValue(框记录,null)与
| :? 字符串形式为str->“'”+str+“”

| :? 选项不,使用F#的内置构造没有好的方法来实现这一点。但是,您可以为这类事情构建自己的可重用活动模式:

open Microsoft.FSharp.Reflection
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Quotations.Patterns

let (|UC|_|) e o =
  match e with
  | Lambdas(_,NewUnionCase(uc,_)) | NewUnionCase(uc,[]) ->
      if (box o = null) then
        // Need special case logic in case null is a valid value (e.g. Option.None)
        let attrs = uc.DeclaringType.GetCustomAttributes(typeof<CompilationRepresentationAttribute>, false)
        if attrs.Length = 1
           && (attrs.[0] :?> CompilationRepresentationAttribute).Flags &&& CompilationRepresentationFlags.UseNullAsTrueValue <> enum 0
           && uc.GetFields().Length = 0
        then Some []
        else None
      else 
        let t = o.GetType()
        if FSharpType.IsUnion t then
          let uc2, fields = FSharpValue.GetUnionFields(o,t)
          let getGenType (t:System.Type) = if t.IsGenericType then t.GetGenericTypeDefinition() else t
          if uc2.Tag = uc.Tag && getGenType (uc2.DeclaringType) = getGenType (uc.DeclaringType) then
            Some(fields |> List.ofArray)
          else None
        else None
  | _ -> failwith "The UC pattern can only be used against simple union cases"
打开Microsoft.FSharp.Reflection
打开Microsoft.FSharp.quotes
打开Microsoft.FSharp.Quotences.DerivedPatterns
打开Microsoft.FSharp.quotes.Patterns
让(| UC | |)e o=
匹配
|Lambdas(u,NewUnionCase(uc,))|NewUnionCase(uc,[])->
如果(框o=null),则
//如果null为有效值,则需要特殊的大小写逻辑(例如Option.None)
设attrs=uc.DeclaringType.GetCustomAttributes(typeof,false)
如果属性长度=1
&&(属性[0]:?>CompilationRepresentationAttribute)。标志和&CompilationRepresentationFlags.UseNullAsTrueValue枚举0
&&uc.GetFields().Length=0
然后是一些【】
没有别的
其他的
设t=o.GetType()
如果FSharpType.IsUnion t,则
设uc2,fields=FSharpValue.GetUnionFields(o,t)
让getGenType(t:System.Type)=如果t.IsGenericType,则t.GetGenericTypeDefinition()否则t
如果uc2.Tag=uc.Tag&&getGenType(uc2.DeclaringType)=getGenType(uc.DeclaringType),则
一些(字段|>数组列表)
没有别的
没有别的
|->failwith“UC模式只能用于简单的联合情况”
现在,您的函数可能如下所示:

let rec getSafeValue (item:obj) = 
    match item with
    | :? string as str -> "'" + str + "'"
    | UC <@ Some @> [v] -> getSafeValue v
    | UC <@ None @> [] -> "null"
    | _ as v -> v.ToString()
let rec getSafeValue(项目:obj)=
匹配项目
| :? 字符串形式为str->“'”+str+“”
|UC[v]->getSafeValue v
|UC[]->“空”
|_uu作为v->v.ToString()

同一笔交易-它限制了记录并选择键入“ath”,这是一种很好的方式。最后我做了一些类似的事情。只是要明确,.NET(因此F#)实际上没有协方差。@GaneshSittampalam-.NET(从4.0开始)确实有协方差:。我认为它没有在F#2.0中实现的原因是F#在发布时主要针对.NET2.0。