foreach loop and generic class

F

fig000

HI,

I'm new to generics. I've written a simple class to which I'm
passing a generic list. I'm able to pass the list and even pass the
type of the list so I can use it to traverse it. It's a generic list
of business objects. I'm able to see that the type is the correct one
in the debugger.

However when I try to traverse the list using the type I can't
compile. The same type variable I've verified as being passed
correctly in the debugger gives the error:

The type or namespace "rectype" could not be found.

This happens when I try to use it in a foreach loop. I tried
implementing IEnumerabler but got compile error from that. Here is the
code. As you can see I've commented out the offending foreach loop. In
the debugger I can see that rectype is the correct underlying type but
I can use it in the foreach loop:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Reflection;


/// <summary>
/// Summary description for BusinessObjectsGeneric
/// </summary>
public class BusinessObjectsGeneric<T>
{
public BusinessObjectsGeneric()
{
//
// TODO: Add constructor logic here
//
}

public DataTable ReturnObjectCollectioAsTable(List<T> GenList,Type
typ)
{

if (GenList == null)
return null;


DataTable dt = new DataTable();
PropertyInfo[] pi = typ.GetProperties();


foreach (PropertyInfo p in pi)
{

dt.Columns.Add(new DataColumn(p.Name, p.PropertyType));

}

Type def = typeof(BusinessObjectsGeneric<T>);
Type rectype = typ;

// foreach (rectype item in GenList)
// {

// }



return dt;

}
}

Any help would be appreciated.

Fig000
 
P

Peter Duniho

HI,

I'm new to generics. I've written a simple class to which I'm
passing a generic list. I'm able to pass the list and even pass the
type of the list so I can use it to traverse it. It's a generic list
of business objects. I'm able to see that the type is the correct one
in the debugger.

However when I try to traverse the list using the type I can't
compile. The same type variable I've verified as being passed
correctly in the debugger gives the error:

The type or namespace "rectype" could not be found.

Well, what exactly are you actually trying to do?

You get the error because "rectype" isn't actually a type you can use
for a variable declaration. It's a class instance of type Type.

You could write something like this:

foreach (T item in GenList)
{
}

but then that begs the question: what will you do with "item" inside the loop?

Why are you passing a Type as a parameter to the method, and how is it
that you really want to use that parameter?

Pete
 
A

Ashot Geodakov

You have a generic list of type T:
List<T> GenList; // = new List<T>();

for each syntax for this list is:

foreach( T item in GenList )
{
// do stuff with the item.
}
 
A

Andrew Faust

You don't need to pass in the actual Type. You just need to make this
method support Generics fully. Try this instead:

public DataTable ReturnObjectCollectionAsTable<T>(List<T> GenList)
{
foreach (T item in GenList)
{
//Code Here
}
}

If you need to make sure T is a class that implements a certain type of
interface or extends some type of object you can constrain the function
with a where clause

public DataTable ReturnObjectCollectionAsTable<T>(List<T> GenList) where T
: IDisposable //Or any other base classes or Interfaces
 
F

fig000

Pete,

Thanks for answering so quickly. What I'm doing is diving in head
first. I realize that I'm going to have to make a lot of mistakes.

What I'm trying to do with the foreach loop is copy the
functionality of a similar loop I found on the net that uses regular
collections instead of generic ones. Here's the code:
========================================================
foreach (object obj in list)
{

object[] row = new object[pi.Length];

int i = 0;



foreach (PropertyInfo p in pi)
{

//row[i++] = p.GetValue(((DataRowView)obj), null);
row = ((DataRowView)obj);
i++;
}



dt.Rows.Add(row);

}

return dt;
==========================================
What I'm hoping to do is to take data from a generic list and put it
into a data table. This is sort of a halfway measure some people have
been using to mix the use of typed objects and .net objects such as
the gridview which, I think, will only take objects that implement
ilist.
So essentially I'm trying to take an existing generic list of business
objects and move the data to a table and then return it. I realize
that my lack of experience may be forcing me to miss the point.

I'd appreciate any help.

Fig000
 
P

Peter Duniho

Pete,

Thanks for answering so quickly. What I'm doing is diving in head
first. I realize that I'm going to have to make a lot of mistakes.

What I'm trying to do with the foreach loop is copy the
functionality of a similar loop I found on the net that uses regular
collections instead of generic ones. Here's the code:

I don't really understand the code. Why is the line calling
PropertyInfo.GetValue() commented out? Is it actually commented out in
the implementation you're trying to replicate? If so, what
relationship does the list of properties from the type have to the
columns in the DataRowView object that's supposed to be in the list?
And regardless, if your list is supposed to contain DataRowView
objects, wouldn't that list of properties always be the properties in a
DataRowView itself?

If the line isn't commented out in the original implementation, why is
it commented here? And why would you want a different property from
each value in each column of the DataRowView?

There's a lot of context missing from the code you posted (you didn't
even post a complete method, never mind showed how the method would be
used, or done the preferred thing and provided a complete code sample
that can be compiled and run without any additional work on our part),
and maybe if you'd provided that context the answers to the above
questions would be apparent. But on the face of it, the code you
posted seems really odd, at least to me.

So far I don't really see anything that using generics is going to help
with. If you really need to enumerate the properties of a class and
fill some data table's columns with the values of those properties, you
can do that without generics. From an instance you can get its type,
from the type you can get the properties, and then of course you can
use reflection to get the values of those properties to fill each row
in your data table.

The only way I could see generics being useful is if you were only
interested in properties that existed in some base class, and you
wanted to deal with List<T> where you could constrain T to inherit that
base class. Then instead of using reflection you could simply use the
properties directly. But as much as I prefer not to use reflection, I
have to admit that having a loop that goes through all of the
properties might be nicer than writing each one out explicitly by name.
And that's assuming that's a valid alternative anyway; nothing in the
code you've posted so far suggests that it is.

Pete
 
F

fig000

Pete,

I probablly commented the code out by accident in trying different
things. Here is the article I got this from.

http://codebetter.com/blogs/brendan.tompkins/archive/2006/05/11/144539.aspx

I'm trying to be able to pass any kind of business object collection
and turn it into a datatable to pass back to a objectdatasource which
in turn will use it for a gridview or formview. If you look at the
article you see that I'm trying to be type free in my creation of this
datatable. It seemed to be suggested by the article.

Fig000
 
P

Peter Duniho

I probablly commented the code out by accident in trying different
things. Here is the article I got this from.

http://codebetter.com/blogs/brendan.tompkins/archive/2006/05/11/144539.aspx

I'm trying to be able to pass any kind of business object collection
and turn it into a datatable to pass back to a objectdatasource which
in turn will use it for a gridview or formview. If you look at the
article you see that I'm trying to be type free in my creation of this
datatable. It seemed to be suggested by the article.

Sorry, I still don't understand. The article you referenced already
doesn't care about the type. It's pretty close to being "type free"
already. What doesn't it accomplish that you want?

In the example code from that article, as long as it supports the IList
interface, you can use any data type to populate a DataTable as shown
in the article. Actually, as near as I can tell, the code in that
article doesn't use anything in IList except the fact that it's
enumerable, so you could actually use IEnumerable as the parameter type
instead.

As far as being "type free" goes, IMHO that's sort of the opposite of
generics. A generic is not really "type free" so much as it allows for
easy creation of multiple concretely typed objects. When used, a
concrete generic instance is actually completely statically typed. I
wouldn't call that "type free". Even though the code in the generic
would not depend on a specific type, the result of using a generic is
very much typed.

Maybe I'm just misunderstanding what you mean by "type free", but I
admit...I still don't get what you're trying to do.

Pete
 
F

fig000

Pete,

I'm sorry I've caused you any frustration. I am learning. You might
call this my proof of concept to see if I want to use generics and
reflection for some basic tasks or (as you pointed out) if I want to.
I hope to finish this procedure and then create add some update, and
insert procs so I can work with dot.net controls such as gridview.
Obviously the update, delete and insert procs don't have to be written
with generics but it would be nice to be able to pass data from the
datatable used to work with the gridview and pass it back to the
generic collection I've been using to keep it current.

The following code is as far as I've gotten. There are two lines that
are important here:

This one seems useless but I'll explain it:

object objthinn = item;

I put that there so I could examine the item object while in the
foreach loop. If I put the cursor over the item object I can see that
it knows what the underlying datatype is (a business class that I
passed with multiple properties) and, to my delight, if I click on the
"+" it actually exposes the whole class and shows me the data in the
record.

Here is the line that I'm stuck on and it's commented out because
it doesn't work a:

//row = (T)item;

What I'm trying to do here is simply get the data out of each
property in this business class record ifrom my generic list
(genlist). I've tried a number of different techniques to make this
line work including various casting methods but I can't seem to make
it work. Item, uncast, exposes some not very useful properties (at
least as far as I can tell).

So that's it. All I want to do is traverse the properties of the
given T type record from genlist currently being used in the foreach
loop and transfer them to the "row" object. This is much like the url
I sent you yesterday.

Here is the whole thing. Again I apologize if I've been unclear and
frustrating. I am really starting from scratch with this:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Reflection;



/// <summary>
/// Summary description for BusinessObjectsGeneric
/// </summary>
public class BusinessObjectsGeneric<T>
{
public BusinessObjectsGeneric()
{
//
// TODO: Add constructor logic here
//
}

public DataTable ReturnObjectCollectioAsTable(List<T> GenList)
{

if (GenList == null)
return null;


DataTable dt = new DataTable();
PropertyInfo[] pi = typeof(T).GetProperties();



foreach (PropertyInfo p in pi)
{

dt.Columns.Add(new DataColumn(p.Name, p.PropertyType));

}


foreach (T item in GenList)
{
T[] row = new T[pi.Length];
object objthinn = item;

int i = 0;




foreach (PropertyInfo p in pi)
{

//row = (T)item;
i++;
}

}



return dt;

}
}

Fig000
 
F

fig000

HI Everyone and especially Pete,

I apologize for dragging everyone through my learning spams. The
answer was in that url I mentioned earlier. I would have thought that
I could get the properties of a class, generic or not by some
interation method. But this works. And Pete was right. My use of a
generic class here added no value over the old collection method. I
learned something and hopefully no one got a headache. I can use this
for any business object class type but I could have used regular
collections for that.

Code:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Reflection;


/// <summary>
/// Summary description for BusinessObjectsGeneric
/// </summary>
public class BusinessObjectsGeneric<T>
{
public BusinessObjectsGeneric()
{
//
// TODO: Add constructor logic here
//
}

public DataTable ReturnObjectCollectioAsTable(List<T> GenList)
{

if (GenList == null)
return null;


DataTable dt = new DataTable();
PropertyInfo[] pi = typeof(T).GetProperties();



foreach (PropertyInfo p in pi)
{

dt.Columns.Add(new DataColumn(p.Name, p.PropertyType));

}


foreach (T item in GenList)
{
object[] row = new object[pi.Length];

int i = 0;



foreach (PropertyInfo p in pi)
{

row = p.GetValue(item,null);
i++;
}
dt.Rows.Add(row);
}



return dt;

}
}
 
P

Peter Duniho

HI Everyone and especially Pete,

I apologize for dragging everyone through my learning spams.

That's okay. Sometimes learning is a struggle. :)
The
answer was in that url I mentioned earlier. I would have thought that
I could get the properties of a class, generic or not by some
interation method. But this works. And Pete was right. My use of a
generic class here added no value over the old collection method.

Well, there _could_ be value, depending on the situation.

In your example, you've made the class generic. Assuming there's a
good reason for making the whole class generic, and assuming you'll
always be passing a List<T> to the method, then you've simplified the
call by one parameter. So that's something. :)

Also note that methods can be generic too. So if that's the only thing
in the class that actually relies on the T parameter, you could instead
make the class a regular class with a generic method defined like this:

public DataTable ReturnObjectCollectionAsTable<T>(List<T> GenList)
{
...
}

And finally, I didn't notice anything in the method that actually uses
an instance member of the class, so assuming it's otherwise
appropriate, you could in fact make the method a static method as well,
allowing you to call it any time, without instantiating an instance of
the class or requiring a pre-instantiated instance of the class.
I
learned something and hopefully no one got a headache. I can use this
for any business object class type but I could have used regular
collections for that.

I have a headache, but it's not because of anything in this newsgroup.
:) Anyway, as you say, you've learned something and I suspect that the
difficulty in making the breakthrough will translate to you recalling
the specifics that much better. :)

Have fun! :)

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top