Reputation: 3745
I have a standard type that I use to pass messages and objects between functions that has an optional MessageObject that is System.Object.
type StatusMessage = {
Message: string
MessageObject: Object option
Success: bool
}
In the following specific function - I know that the Message Object will always contain the following specific type and I want to be able to access that within the function
type SingleCorrectRecord = {
CardTransactionWithOrder: CardWithOrder
Line: RowTransaction
ExchangeVariance: decimal
}
My function is:
let getEstimatedVariance(matchedTransactions: StatusMessage list): decimal =
let exchangeVariance:decimal =
matchedTransactions |> Seq.sumBy(fun mt -> mt.MessageObject.ExchangeVariance)
estimatedVariance
Obviously mt.MessageObject doesn't contain the property "ExchangeVariance" but I need to be able to cast (or unbox?) the object so that it knows that it is a SingleCorrectRecord type and I can access the properties.
Any help is appreciated.
Upvotes: 3
Views: 305
Reputation: 1685
:?>
is the downcast operator (or :?
within pattern matching) which can be used for this problem. However, it is typically not recommended to use downcasting, which can fail at runtime, in F# code.
As an alternative, you could structure your StatusMessage
type to be generic or to use a discriminated union depending on whether messages with different payload types need to be stored in the same collection.
// This type can store any type of message however StatusMessage<SingleCorrectRecord> is
// a different type to StatusMessage<Other> and they can't be stored in the same collection.
type StatusMessage<'T> = {
Message: string
MessageObject: 'T option
Success: bool
}
let getEstimatedVariance(matchedTransactions: StatusMessage<SingleCorrectRecord> list): decimal =
let estimatedVariance:decimal =
matchedTransactions |> Seq.sumBy(fun mt ->
match mt.MessageObject with
| Some msg -> msg.ExchangeVariance
| None -> 0M )
estimatedVariance
If the messages need to be in a grouped collection you could define all messages in a MsgPayload
discriminated union:
type MsgPayload =
| SingleCorrectRecord of SingleCorrectRecord
| Other of string
type StatusMessage2 = {
Message: string
MessageObject: MsgPayload option
Success: bool
}
let getEstimatedVariance2(matchedTransactions: StatusMessage2 list): decimal =
let estimatedVariance:decimal =
matchedTransactions |> Seq.sumBy(fun mt ->
match mt.MessageObject with
| Some (SingleCorrectRecord msg) -> msg.ExchangeVariance
| _ -> 0M )
estimatedVariance
Upvotes: 4
Reputation: 5741
You can nest the dynamic type test with the union case pattern in the same match expression:
let exchangeVariance =
matchedTransactions |> Seq.sumBy (fun mt ->
match mt.MessageObject with
| Some(:? SingleCorrectRecord as scr) -> scr.ExchangeVariance
| _ -> 0M )
// val exchangeVariance : decimal
Upvotes: 4