tags:

views:

227

answers:

6

Hi,

EDIT AGAIN: the solution was probably different from my original question. Thanks everyone very much your great ideas. I wish I could vote for more than one answer.

EDIT: I am populating a Jquery table plugin from datatables/.net and it requires the data (Json) to be in a certain format like this;

    "sEcho": 1,
    "iTotalRecords": 57,
    "iTotalDisplayRecords": 57,
    "aaData": [
        [
            "Gecko",
            "Firefox 1.0",
            "Win 98+ / OSX.2+",
            "1.7",
            "A"
        ],
        [
            "Gecko",
            "Firefox 1.5",
            "Win 98+ / OSX.2+",
            "1.8",
            "A"
        ],
        ...
    ] 
}

I am recieving data from a service that is returning a collection of object. I would like one method which I can pass these collections into and it will return the appropriate string

thanks END EDIT I would like to build a method that can receive and object that we build and will return an array List each containing the value of each object passed in. For example;

I have a collection of 'Car' objects

What I would like to do is

public object[] Something<T>(_cars)
{
    object[] objArray = new object[_cars.Count];
    foreach(Car _car in _cars ){
    IList objList = new List<string>;
    objList.Add(_car.Color);
    objList.Add(_car.EngineSize);
    //etc etc
    objArray[i] = objList;//i'll have to use a for loop to get the i counter but you get my idea
   }
    return objArray
}

my problem is how can I access the properties of the object without knowing what type of object it is?

thanks for any help

A: 
IList objList = new List<string>();
foreach ( PropertyInfo prop in _car.GetType().GetProperties() )
{
    var value = prop.GetValue( _car, null );
    objList.Add( value != null ? value.ToString() : null );
}
objArray[i] = objList;
Tinister
The most non generic generic method of all time...
Ed Swangren
...and then you downvoted my answer? Wow, immature much?
Ed Swangren
Nah, I didn't downvote it.
Tinister
Oh... we'll my apologies then :)
Ed Swangren
No problems, Ed. I'll also gladly take any suggestions on how to improve my answer. =)
Tinister
Hi everyone,I really appreciate your help on this but your comments off subject really isn't helping me. Would it be possible to do that somewhere else? Thanks again for your continuing help. I'll edit my original question to include what I am trying to do completely.
kurasa
I think the real issue here is not how to make the generic method work, but why do you want to use a generic method for this in the first place? Only your own classes will have a property like "EngineSize", so just take an IList<MyClass> as an input and be done with it.
Ed Swangren
@Ed, I agree maybe a generic method is not appropriate. I was hoping for the best solution without having to perform the same (similar) function for every collection but maybe there is no other solution besides that. Reflection does sound a bit ~
kurasa
A: 

my problem is how can I access the properties of the object without knowing what type of object it is?

Well, in the general sense you can't. Generics is all about treating objects generically. However, you can impose type constraints by using a where clause. Based on the foreach loop I would say constrain your types to types that implement IEnumerable, but then you go on to use properties like "Color" and "EngineSize", which are very specific. I don't even know why you would have properties named "Color" and "EngineSize" that are strings, but that is another problem altogether...

It seems like the best approach for you would be to define an interface or an abstract base class that each of these objects inherits from. Then you can use the 'where' clause to constrain to objects of that interface/base class only So...

public object[] Something<T>( T _cars) where T : IEnumerable<MyInterface>

However, if we are going to go down this road I don't see why the method should be generic at all. It could simply take an IEnumerable<T> as an input. When we only want to use one type in a method generics is not needed.

Ed Swangren
the most generic non-generic answer of all time :)
Russ Cam
People really liked that eh? :)
Ed Swangren
@Ed - your answer seemed deprived of its generic comment membership
Russ Cam
...and then someone downvotes this answer. Care to explain why? If you have a better solution I would like to see it. I am no expert here, but downvoting just because I downvoted your answer is silly.
Ed Swangren
@Ed you're not in the reflection club ;)
Rex M
I guess not :). I would still like to know the reason for the downvote though. If there is a better answer I would be interested to hear it. To be honest I don't use generics all that often and there are people around here who are much more knowledgeable about this topic than I am.
Ed Swangren
Hi,the only problem I see with this is that the object can be so different for example it can be a Car but it could also be a Computer object or a Chair object or a Phone object. The objects will not necessarily contain the same properties
kurasa
They do if they implement the same interface or ABC as I suggested.
Ed Swangren
Hi Ed,I am interested in your last comment but I am not sure I understand what you mean. Sorry for soundsing like uch a noob but could you give a small example :)thanks
kurasa
Also, 'Color' and 'EngineSize' are not strings they could be anything but I have to return them as string
kurasa
What Ed means is that if all of the objects (e.g. Car, Computer, etc) implement some common interface, then your function can use that interface to "ask" the object for its array elements, instead of having to guess.
Annabelle
no. They do not implement a common interface and there in lies the entire problem. If they did then there would not be an issue :)
kurasa
A: 

The code to get the Property values of an object is

foreach (PropertyInfo info in myObject.GetType().GetProperties())
{
   if (info.CanRead)
   {
      object o = propertyInfo.GetValue(myObject, null);
   }
}
Russ Cam
The most non generic generic method of all time...
Tinister
@Tinister - the most non-generic generic comment of all time :) I never said it was a good idea...
Russ Cam
+3  A: 

Update: To answer your revised question - produce a JSON result of a data structure - use the built-in JavaScriptSerializer class:

JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = seriaizer.Serialize(myObjectOrArray);

Below is the previous answer.

how can I access the properties of the object without knowing what type of object it is

Using Reflection, and grabbing the properties which are strings. Note this is not necessarily a good idea. The fact that you have to use reflection to get what you want is usually a HUGE WARNING FLAG that your design is wrong.

However, in the hopes of learning something useful, here's how it could be done:

public object[] Something<T>(T[] items)
{
    IList objList = new List<object>();
    //get the properties on which are strings
    PropertyInfo[] properties = typeof(T).GetProperties().Where(p => p.PropertyType == typeof(string));
    foreach(T item in items)
    {
        IList stringList = new List<string>;
        foreach(PropertyInfo property in properties)
        {
            objList.Add(property.GetValue(item, null) as string);
        }
        objList.Add(stringList);
    }
   }
   return objList.ToArray();
}

A far, far better solution would be to require all the objects coming into this method to conform to some interface that requires them to provide their own string-formatted data. Or maybe take two steps back and ask for help on the underlying problem. This approach is fraught with problems. It's a rabbit hole you don't want to go down.

Rex M
Answer #3 containing the most non generic generic method of all time. I'm so glad I lost rep on this.
Tinister
@Tinister no one said it's a good idea :)
Rex M
If you wanted all the property values you could remove the Where constraint on GetProperties() and call objList.Add(property.GetValue(item, null).ToString()) in the loop.
Jamie Ide
@Jamie hopefully the extra information can help make an informed decision about what to actually do. This is not a proposed solution, just a demonstration.
Rex M
Hi everyone,I really appreciate your help on this but your comments off subject really isn't helping me. Would it be possible to do that somewhere else? Thanks again for your continuing help. I'll edit my original question to include what I am trying to do completely.
kurasa
thanks. The problem still remains of how I get the objects into the object array without the field names and removing the correct curly braces
kurasa
Note that the Framework makes no guarantees about the order of properties returned by Type.GetProperties(). In fact, "your code must not depend on the order in which properties are returned, because that order varies." [http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx][1]
Annabelle
Oops, mangled that URL: http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx
Annabelle
@Douglas makes a good point. You might be better off trying to fix the grid control than twisting yourself into a pretzel trying to conform to the current format.
Rex M
yes, all good points. I have posted a question to the author of the table to get his take on it. Until then I'll just repeat the code...bit of a shame
kurasa
+2  A: 

Use the System.Web.Script.Serialization.JavaScriptSerializer class. It was specifically provided for JSON serialization.

using System.Web.Script.Serialization;

public string ToJson(object o)
{
  JavaScriptSerializer serializer = new JavaScriptSerializer();
  return serializer.Serialize(o);
}

EDIT: Oops, I missed that your plugin doesn't want a true JSON representation of the objects; it just wants arrays of values. You could use reflection to iterate over the properties of the objects as others have suggested, but then you have no control over which properties end up in which columns. It is not clear from your question whether that is a problem for you.

If you need a strict mapping between properties and columns, then you will have to define that somehow in C#. To do this you could implement IEnumerable as Ed demonstrates or create a custom interface:

public interface ITableDataSource
{
  IList<string> GetTableData();
}

Then implement this on any objects that might need to be data sources for the jQuery table plugin:

public class Car : ITableDataSource
{
  //...class implementation details...

  public IList<string> GetTableData()
  {
    return new List<string>()
    {
      this.Color,
      this.EngineSize,
      this.NumberOfSeats.ToString()
    };
  }
}

Finally, in your method that is returning the data to the jQuery plugin, use the interface to construct your response object, then pass it to my ToJson() method to serialize it:

public string DoSomething(IList<ITableDataSource> objects)
{
  var result = new 
  {
    sEcho = 1,
    iTotalRecords = 1,
    iTotalDisplayRecords = 1,
    aaData = new List<IList<string>>()
  };
  foreach (ITableDataSource ds in objects)
    result.aaData.Add(ds.GetTableData());

  return ToJson(result);
}
Annabelle
tried that and it does not return the right format. It return valid Json but not the Json that this plugin requiresit returns{"sEcho":1,"iTotalRecords":10,"iTotalDisplayRecords":10,"aaData":[[{"Job":"Plumber","Name":"John"}],[{"Job":"Plumber2","Name":"John2"}]]}the grid does not cope with the field names and the semi colon and curly braces
kurasa
Ah, missed that part. It's not clear from your question if you need strong binding between object properties and positions in the arrays. If you don't, any of the reflection-based methods others have posted should work for constructing those arrays. In case strong binding is important, I've updated my answer with a possible solution.
Annabelle
+1  A: 

While it would be relatively straightforward to use reflection to loop through all of your objects and all the properties on those objects to build that string, it's already been written.

I would highly recommend looking at the Json.NET project found here. Add this DLL to your project and converting a list of objects into a Json formatted string is as easy as:

string json = Newtonsoft.Json.JsonConvert.SerializeObject( listOfCars );
Tinister