Я считаю, что наиболее полезно использовать Runnable для всех упомянутых причин, но иногда мне нравится продлить Thread, поэтому я могу создать свой собственный метод остановки потока и вызвать его непосредственно на созданном мной потоке.
Я думаю, что понял, но потребовалось некоторое время, чтобы понять, как работать с выражениями. Я сослался на историю этого поста [117], чтобы узнать, как построить System.Linq.Expressions.Expression
. Вот что у меня есть:
open System.Linq.Expressions
open Microsoft.FSharp.Linq.RuntimeHelpers
...
let toProdRptExpr : Expression<Func<CostItem, ProductionReport>> =
<@ Func<_, _> (fun (i:CostItem) -> i.ProductionReport) @>
|> LeafExpressionConverter.QuotationToExpression
|> unbox<Expression<Func<CostItem, ProductionReport>>>
let toCostItemsExpr : Expression<Func<ProductionReport, seq<CostItem>>> =
<@ Func<_,_> (fun (pr:ProductionReport) -> pr.CostItems) @>
|> LeafExpressionConverter.QuotationToExpression
|> unbox<Expression<Func<ProductionReport, seq<CostItem>>>>
let a = builder.HasOne(toProdRptExpr)
let b = a.WithMany(toCostItemsExpr)
это намного более многословно, чем нужно, но это помогло мне понять, как типы сочетаются друг с другом.
РЕДАКТИРОВАТЬ
Для краткости вы можете создать функцию типа
let toExpr (f:'a -> 'b) =
<@ Func<_,_> (f) @>
|> LeafExpressionConverter.QuotationToExpression
|> unbox<Expression<Func<'a, 'b>>>
и затем использовать ее как
builder
.HasOne(toExpr(fun (i:CostItem) -> i.ProductionReport))
.WithMany(toExpr(fun (pr:ProductionReport) -> pr.CostItems))
[1114 ] Но вы должны быть осторожны, потому что похоже, что CostItem и ProductionReport являются взаимно-ссылочными (см. Обсуждение в комментариях ниже). Это означает, что они должны быть определены в одном файле и использовать ключевое слово and
(см. этот пример)