何时使用F#' typedefof<> T>与typeof<&#; T>?

时间:2018-06-13 13:59:28

标签: f#

有人可以澄清何时使用typedefof<'T>typeof<'T>

typedefof<System.String>typeof<System.String>都会返回相同的Type个实例。

但是,它们会为System.Collections.Generic.List<_>返回不同的实例和不同的信息。

我可以将typedefof视为新的typeof吗?我应该切换到始终使用typedefof吗?还是比它更微妙?

3 个答案:

答案 0 :(得分:8)

这应该说明不同之处。使用typeof时,编译器会推断类型参数并构造具体类型。在这种情况下,推断的类型参数是System.Object

let t1 = typeof<System.Collections.Generic.List<_>>
let t2 = typedefof<System.Collections.Generic.List<_>>

printfn "t1 is %s" t1.FullName
printfn "t2 is %s" t2.FullName

输出:

t1 is System.Collections.Generic.List`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
t2 is System.Collections.Generic.List`1

因为typeof只能返回构造的类型,所以如果你需要一个表示泛型类型定义的类型对象,则需要typedefof

答案 1 :(得分:7)

当您想要获取给定类型的typeof对象时,将使用

System.Type。如果要获取表示泛型类型的类型定义的typedefof,则使用System.Type。作为使用两者的示例,假设您有一个名为Generic<'a>的类型,并且您想要创建一个函数,该函数返回任何给定类型的System.Type的{​​{1}}对象。

Generic

在这里,您可以使用type Generic<'a> = Value of 'a let makeGenericOf<'a> () = typedefof<Generic<_>>.MakeGenericType(typeof<'a>) 函数来获取类型定义,并typedefof使用typeof来构建通用'a Generic<'a> }。

答案 2 :(得分:1)

我非常感谢phoog,Aaron和JLRishe的回答。以下是我根据他们的答案和我自己的实验所学到的知识。

有两个Type个实例与泛型相关联。

  1. 与通用关联的Type具有特定的类型参数。例如,TypeList<int>相关联,TypeList<string>相关联。这是您使用typeof<>时获得的。

    > typeof<List<string>>.ToString();;
    val it : string = "Microsoft.FSharp.Collections.FSharpList`1[System.String]"
    
    > typeof<List<int>>.ToString();;
    val it : string = "Microsoft.FSharp.Collections.FSharpList`1[System.Int32]"
    
  2. 有一个Type与泛型类型定义本身相关联。例如,与Type关联的单个List<'T>List<int>List<string>List<_>相同。这是您使用typedefof<>时获得的。

    > typedefof<List<string>>.ToString();;
    val it : string = "Microsoft.FSharp.Collections.FSharpList`1[T]"
    
    > typedefof<List<int>>.ToString();;
    val it : string = "Microsoft.FSharp.Collections.FSharpList`1[T]"
    
    > typedefof<List<_>>.ToString();;
    val it : string = "Microsoft.FSharp.Collections.FSharpList`1[T]" 
    
  3. 顺便说一句,Type类有GetGenericTypeDefinition()的实例方法。这意味着,以下两个返回相同的实例:

        > Object.ReferenceEquals(typeof<List<int>>.GetGenericTypeDefinition(), typedefof<List<int>>);;
        val it : bool = true        
    

    如果致电typeof<List<_>>会怎样?如phoog所述,您可以获得Type List<Object>的定义。

    > typeof<List<_>>.ToString();;
    val it : string = "Microsoft.FSharp.Collections.FSharpList`1[System.Object]"
    

    这有助于理解。例如,假设我需要知道对象是否是通用列表(任何类型)。

    // does not give me the answer I naively expected
    > o.GetType() = typeof<List<_>>;; 
    val it : bool = false
    
    // does this reference point to a List<'T>?
    > o.GetType().IsGenericType && o.GetType().GetGenericTypeDefinition() = typedefof<List<_>>;;
    val it : bool = true
    

    此外,如果您想要后期实例化泛型类型,可以使用Aaron提到的MakeGenericType(...)方法。

    > let myList = typedefof<List<_>>.MakeGenericType(typeof<int>);;
    val myList : Type = Microsoft.FSharp.Collections.FSharpList`1[System.Int32]