Когда использовать typedefof <'T> в F # против typeof <' T>? - PullRequest
0 голосов
/ 13 июня 2018

Может кто-нибудь уточнить, когда использовать typedefof <'T> против typeof <' T> ?

Оба typedefof<System.String> и typeof<System.String> возвращаюттот же Type экземпляр.

Однако они возвращают разные экземпляры и различную информацию для System.Collections.Generic.List<_>.

Могу ли я думать о typedefof как о новом и улучшенном typeof?Должен ли я просто переключиться на всегда, используя typedefof?Или это более тонко, чем это?

Ответы [ 3 ]

0 голосов
/ 13 июня 2018

Это должно проиллюстрировать разницу.Когда вы используете 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 необходимо, есливам нужен объект типа, представляющий определение универсального типа.

0 голосов
/ 17 июня 2018

Я действительно ценю ответы Фога, Аарона и Дж.Л. Рише.Вот то, что я узнал, основываясь на их ответах и ​​моих собственных экспериментах.

Есть два Type экземпляра, связанных с генериками.

  1. Есть Type связано с универсальным, который имеет определенные параметры типа.Например, Type связан с List<int>, а другой Type связан с List<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]" 
    

Кстати, класс Type имеет метод экземпляра для GetGenericTypeDefinition().Это означает, что следующие два возвращают один и тот же экземпляр:

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

Что произойдет, если вы позвоните typeof<List<_>>?Вы вернули определение 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

Кроме того, если вы хотите создать экземпляр универсального типа с поздним связыванием, вы можете использовать MakeGenericType(...) метод, о котором говорил Аарон.

> let myList = typedefof<List<_>>.MakeGenericType(typeof<int>);;
val myList : Type = Microsoft.FSharp.Collections.FSharpList`1[System.Int32]
0 голосов
/ 13 июня 2018

typeof используется, когда вы хотите получить объект System.Type для данного типа.typedefof используется, когда вы хотите получить System.Type, который представляет определение типа для универсального типа.В качестве примера, который использует оба, предположим, что у вас есть тип с именем Generic<'a>, и вы хотите создать функцию, которая возвращает объект System.Type для Generic любого данного типа.

type Generic<'a> = Value of 'a

let makeGenericOf<'a> () = 
    typedefof<Generic<_>>.MakeGenericType(typeof<'a>)

Здесь вы должны использовать функцию typedefof для получения определения типа и typeof для получения типа 'a для построения универсального Generic<'a> Type.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...