How to convert a business object to a string using Stringbuilder

How to convert a business object to a string using Stringbuilder

Old forum URL: forums.lhotka.net/forums/t/3558.aspx


yimiqi posted on Monday, September 17, 2007

You can convert a dataset or dataview to a tab, comma or any character separated string using StringBuilder, as follows (a comma separated string in this example):

            Dim StrObj As New System.Text.StringBuilder

            Dim aCol As DataColumn
            For Each aCol In srcDataView.Table.Columns
                   StrObj.Append(aCol.ColumnName)
                   StrObj.Append(",")
            Next
          Dim aRow As DataRowView
            For Each aRow In srcDataView
                For Each aCol In srcDataView.Table.Columns
                       StrObj.Append(aRow(aCol.ColumnName))
                       StrObj.Append(",")
                Next aCol
          Next aRow
          Return StrObj.ToString()

This is all straightforward.

But If I have a ReadOnlyList ProjectList ( it is the collection of the ReadOnly object ProjectInfo) in place of the dataview in the example and try to achieve the same results (convert the list of ProjectInfo to a comma separated string), how do I go about doing that? 

The part I'm stuck is that what qualifier I should use to access the column names in ProjectInfo object and be able to loop through them?  Has anyone done similar implementation as this?  The column names are properties of the ProjectInfo object.

Thanks in advance. 

xal replied on Monday, September 17, 2007

Unfortunately, you'll have to fallback to hand coding it property by property or use reflection in order to read all the properties dynamically.

Andrés

yimiqi replied on Monday, September 17, 2007

Hummm, hard coding all the column names seems a bit akward.  Do you have code sample how to use reflection get all the properties dynamically?

By the way, are you the Cslagen guy?  I think you are.   Great tool,  I use it to gen all my BOs.

Thank you for the suggestion on my problem, and hats off to all your hard work on Cslagen.

JoeFallon1 replied on Monday, September 17, 2007

Here is some reflection code that should get you started:

Protected mProps As List(Of PropertyInfo)

Private ReadOnly Property Props() As List(Of PropertyInfo)
 
Get
   
If mProps Is Nothing Then
     
mProps = New List(Of PropertyInfo)

      'This code ensures you get the correct Type of a ROC based on the Item method which uses index As Integer.
      'I have 2 overloads of the Item method which can cause problems if you do not specify the correct one.
     
Dim infoType As Type = mROC.GetType().GetProperty("Item", New Type() {GetType(Integer)}).PropertyType

      'get an array of all Properties of the ROC (could be 50 or more)
     
Dim tempProps() As PropertyInfo = infoType.GetProperties(flags)

      'add all Properties to mProps. Other conditional code was removed for clarity.
     
For Each prop As PropertyInfo In tempProps
        mProps.Add(prop)
     
Next
    
End If

   
Return mProps

  End Get
End Property

Joe

yimiqi replied on Monday, September 17, 2007

Thank you Joe, for posting the reflection code sample.

I don't exactly know how I am going to use the code to do what I'm trying to achieve yet, but this definitly will get me started in that direction.  I will post back on progress.

Thanks.

yimiqi replied on Wednesday, September 19, 2007

I'm back...  

Joe, what flags am  I supposed to use in the following statement?  I used BindingFlags.Default, .GetField and .GetProperty, all gave me Nothing back (tempProps.length = 0).  So, the mProps also returns Nothing.

  'get an array of all Properties of the ROC (could be 50 or more)
     
Dim tempProps() As PropertyInfo = infoType.GetProperties(flags)

Apparently I missed something, but what was it? 

 

JoeFallon1 replied on Wednesday, September 19, 2007

 Protected flags As BindingFlags = BindingFlags.Public Or BindingFlags.IgnoreCase Or BindingFlags.Instance

Joe

yimiqi replied on Wednesday, September 19, 2007

Thanks Joe, that worked.  BindingFlag has about 20 enum values you could set, I was very confused with what values to use.

That part worked, now I'm getting something back, following is in the command window

>? tempprops

{Length=14}

(0): {System.Reflection.RuntimePropertyInfo}

(1): {System.Reflection.RuntimePropertyInfo}

(2): {System.Reflection.RuntimePropertyInfo}

....

(14): {System.Reflection.RuntimePropertyInfo}

Versus before, length was 0.

But, when I tried to add the propertyinfo in tempprops to the property list as in your sample code, I got NullReferenceException was unhandled error - I probably be able to figure this one out myself

 For Each prop As PropertyInfo In tempProps
        mProps.Add(prop)
     
Next

But any insights is always welcome.

I'm new to reflection, please bare with all my newbie questions. 


xal replied on Wednesday, September 19, 2007

Try something like this.  You probably want to make adjustments to order the properties or something, but this should get you 80% there... Just pass an object to the function and get the string.


Public Shared Function ObjToString(ByVal obj As Object) As String
        Dim sb As New System.Text.StringBuilder()
        Dim t As Type = obj.GetType()

        Dim props() As System.Reflection.PropertyInfo = t.GetProperties(Reflection.BindingFlags.Public Or Reflection.BindingFlags.Instance)
        For Each p As System.Reflection.PropertyInfo In props
            Dim val As Object = p.GetValue(obj, Nothing)
            Dim stringVal As String
            If val Is Nothing Then
                stringVal = "Null Reference"
            Else
                stringVal = val.ToString()
            End If
            sb.AppendFormat("{0}: {1}", p.Name, stringVal)
            sb.AppendLine()
        Next
        Return sb.ToString()
    End Function



Andrés

yimiqi replied on Wednesday, September 19, 2007

Andrés

Thank you for posting the reflection code.  I wish I knew a bit more about refection so that not to bother you guys with such basic simple questions here.

With your and Joe's code, I think I'm going to (I'll have to) accomplish my requirement.

Just in case you are interested, there is another post in this forum discussing export data from BO to a CSV string then file.  The author of that post didn't use reflection to do his work.

http://forums.lhotka.net/forums/17708/ShowThread.aspx#17708

yimiqi replied on Thursday, September 20, 2007

Joe or Andrés

I'm getting the TargetException was unhandled error "Object does not match target type" when at line

           Dim val As Object = p.GetValue(obj, Nothing)

If I replace  line    Dim t As Type = obj.GetType()

with         Dim t As Type = obj.GetType().GetProperty("Item", New Type() {GetType(Integer)}).PropertyType
(from Joe's)

I did that because the line from Joe's code ensures getting the correct type of a ROC object based on the item method which uses index as integer, which is what I wanted - the item properties of the object.

obj.GetType() gives me all other properties of the object, like AllowRemove, AllowEdit, AllowNew etc. which isn't what I wanted.

If I don't change that line, the GetValue works for the first 4 properties, then will also fail but on different error - TargetParameterCountException ("Parameter count mismatch)

But I'm more concerned with the TargetException error.

So, is there a different way to get the value of an object's item properties (= column names, e.g firstname, age etc.) other than using GetValue(obj, Nothing)?

Thanks in advance for any help.  (I will do some lookup on reflection too)

 

yimiqi replied on Thursday, September 20, 2007

If I don't change that line, the GetValue works for the first 4 properties, then will also fail but on different error - TargetParameterCountException ("Parameter count mismatch)

I found out what caused the ParameterCountException error.

When you use this line of code: Dim t As Type = obj.GetType()

Then do GetProperties, you will get list of propertyinfo like AllowRemove, AllowEdit, AllowNew, Count etc. and Item. 

When you loop through each p as propertyinfo in the property list to GetValue, when hits the Item propertyinfo  in the loop, you will get the above parameter error.  It makes sense, because Item propertyinfo has its own child collection (the item properties of the object - in my case is the collection of my grid column names I'm after to build a string for).  This problem can be resolved by replace one line of code (as in my last message in this thread).

But, my headache problem still there, TargetException was unhandled error "Object does not match target type" [;)Smile [:)]]

I did a bit search on PropertyInfo.GetValue() on MSDN and found the following

PropertyInfo.GetValue Method

But I'm lost as to what values I should set as parameters when Call GetValue(). I'm using GetValue(obj, Nothing), and this one gives me the target type exception error. 

Could you help me out?  Thanks in advance.

yimiqi replied on Friday, September 21, 2007

I figured out the problem.

the obj value passed in calling GetValue(obj, Nothing) is a ROC object.  But when I use

 Dim t As Type = obj.GetType().GetProperty("Item", New Type() {GetType(Integer)}).PropertyType to get the type

rather than

Dim t As Type = obj.GetType()

then to get the properties of t, I need to pass in the  ROC's child object - RO object (e.g. ProjectInfo in ProjecList)

when propertyinfo.name = "Item", if you want to get all the properties exposed in the ROC.

Thanks.

xal replied on Friday, September 21, 2007

The code I sent is not intended to loop through collections by itself. It's just code for getting properties for a single instance.
If you need all the "ToStrings" in a collection, then you should loop through the collection and run each item agains the method I sent.

Otherwise, you'll have to use recursion, but first checking that the properties don't have indexers.
I assume you don't want to get the properties for the collection itself, just the items in the collection. Right?

Andrés

yimiqi replied on Friday, September 21, 2007

xal:

I assume you don't want to get the properties for the collection itself, just the items in the collection. Right?

Andrés

That's correct.  I only want to get the items in the collection.  E.g. ROC object ProjectList has its properties, and item is one of them. Item then has its own properties which is a list of public properties/fields (=column names) exposed by the business object.  Item actually is the RO object, ProjectInfo in this case.  I only want to get all the properties/fields in ProjectInfo.

Thanks for the help.

xal replied on Friday, September 21, 2007

So again, loop through the list yourself and pass each of the items to the method I sent you.

Andrés

yimiqi replied on Friday, September 21, 2007

Got it. Thanks a lot.

Copyright (c) Marimer LLC