Как мне создать Произвольный для System.Type?
Я пытаюсь инициализировать мои модельные объекты с помощью FsCheck. Модели живут в C# и обычно инициализируются через Entity Framework через свои частные установщики. Например (надумано):
public class Model
{
public string One { get; private set; }
public int Two { get; private set; }
}
Я хотел бы создать генератор FsCheck, который автоматически использует зарегистрированный генератор для каждого свойства для создания модели. Что-то вроде этого:
let modelGenerator =
gen {
let incident = new Model()
typeof<Model>.GetProperties()
|> Array.filter (fun p -> p.CanWrite)
|> Array.iter (fun p ->
let! newVal = Arb.generateType p.PropertyType // I wish I could do this
p.SetValue(incident, newVal))
return incident
}
Есть две вещи не так с этим:
let!
не может использоваться за пределамиgen
Вычислительное выражение.Arb.generateType
не существует, и я не могу найти способ сделать его эквивалент
Можно ли создать генератор, который будет автоматически устанавливать личные поля в моей модели?
1 ответ
Решение
С силой отражения все возможно (или бросает во время выполнения).
module Arb =
open System.Reflection
// this is just a helper type to do reflection on.
type internal GenerateInvoker =
static member Invoke<'typ> () =
Arb.generate<'typ>
|> Gen.map box
// Invokes a generic method using a runtime type as a generic argument.
let generateType (typ: Type) =
typeof<GenerateInvoker>
.GetMethod("Invoke", BindingFlags.Static ||| BindingFlags.NonPublic)
.MakeGenericMethod([|typ|])
.Invoke(null, [||]) :?> Gen<obj>
let modelGenerator =
gen {
let incident = new Model()
let props =
typeof<Model>.GetProperties()
|> Array.filter (fun p -> p.CanWrite)
// gen builder implements For, so you can do something like this.
for prop in props do
let! newVal = Arb.generateType prop.PropertyType
prop.SetValue(incident, newVal)
return incident
}
Gen.sample 1 3 modelGenerator