views:

70

answers:

2

I'm trying to iterate through an array of objects and recursively print out each objects properties.
Here is my object model:

type firmIdentifier = {
    firmId: int ;
    firmName: string ;
}
type authorIdentifier = {
    authorId: int ;
    authorName: string ;
    firm: firmIdentifier ;
}

type denormalizedSuggestedTradeRecommendations = {
    id: int ; 
    ticker: string ;
    direction: string ;
    author: authorIdentifier ;
}

Here is how I am instantiating my objects:

let getMyIdeasIdeas = [|
     {id=1; ticker="msfqt"; direction="buy"; 
        author={authorId=0; authorName="john Smith"; firm={firmId=12; firmName="Firm1"}};};

     {id=2; ticker="goog"; direction="sell"; 
        author={authorId=1; authorName="Bill Jones"; firm={firmId=13; firmName="ABC Financial"}};};

     {id=3; ticker="DFHF"; direction="buy"; 
        author={authorId=2; authorName="Ron James"; firm={firmId=2; firmName="DEFFirm"}};}|]

And here is my algorithm to iterate, recurse and print:

let rec recurseObj  (sb : StringBuilder) o=
            let props : PropertyInfo [] = o.GetType().GetProperties()
            sb.Append( o.GetType().ToString()) |> ignore
            for x in props do
                let getMethod = x.GetGetMethod()
                let value = getMethod.Invoke(o, Array.empty)
                ignore <|
                        match value with
                        | :? float  | :? int | :? string | :? bool as f -> sb.Append(x.Name + ": " + f.ToString() + "," ) |> ignore
                        | _ ->  recurseObj  sb value
 for x in getMyIdeas do
                recurseObj sb x
                sb.Append("\r\n") |> ignore

If you couldnt tell, I'm trying to create a csv file and am printing out the types for debugging purposes. The problem is, the first element comes through in the order you'd expect, but all subsequent elements come through with a slightly different (and confusing) ordering of the "child" properties like so:

RpcMethods+denormalizedSuggestedTradeRecommendationsid: 1,ticker: msfqt,direction: buy,RpcMethods+authorIdentifierauthorId: 0,authorName: john Smith,RpcMethods+firmIdentifierfirmId: 12,firmName: Firm1,

RpcMethods+denormalizedSuggestedTradeRecommendationsid: 2,ticker: goog,direction: sell,RpcMethods+authorIdentifierauthorName: Bill Jones,RpcMethods+firmIdentifierfirmName: ABC Financial,firmId: 13,authorId: 1,

RpcMethods+denormalizedSuggestedTradeRecommendationsid: 3,ticker: DFHF,direction: buy,RpcMethods+authorIdentifierauthorName: Ron James,RpcMethods+firmIdentifierfirmName: DEFFirm,firmId: 2,authorId: 2,

Any idea what is going on here?

+1  A: 

Does adding this help?

        for x in props |> Array.sortBy (fun p -> p.Name) do 
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In general, I think reflection returns entities (like attributes, methods, properties) in an unspecified order. So just pick a fixed sort order?

(Or did I misunderstand the issue?)

Brian
I'd end up with the same problem because the first element has authorName and RpcMethods+authorIdentifierauthorId as .Name and the subsequent ones have RpcMethods+authorIdentifierauthorName and authorId. My real question is why is the first element configured differently from all subsequent elements of the same type as least as far as reflection is concerned?
PhilBrown
Ok, I understand the question now, but I am not seeing the behavior you're seeing. What version of F# are you using?
Brian
@Brian - I think .NET version may matter too; as I recall there was a change in the reflection order between .NET 2.0 and 2.0 SP1.
kvb
I'm using f# 4, .NET 4, and it's a silverlight 3 application
PhilBrown
A: 

This is a reflection thing. You can't rely on the order of the properties using reflection. I need to sort using MetaTokens. I will post this solution when I get around to implementing it.

PhilBrown
I took another route. My objects were being used to populate a datagrid. I was converting some of the columns from float values to text in a textbox and could no longer sort these columns so I used the sortMemberPath to allow sorting. I then wrote a recursive algorithm that takes an object and a pathname that returns the object your looking for.
PhilBrown