Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Dynamically Typed List

Posted on 2013-01-17
11
26 Views
Last Modified: 2016-07-02
Hi There

I'm trying to create a static function in c# .net that I can use to turn a line of MySQL in to a List<T> where T is of a generic type.

I find myself repeatedly creating the following code for each type that I use it for (in this case, the type Train)

        private static List<Train> GetTrainListFromSQL(string sql)
        {
            DataTable dt = DB.GetTable(sql);
            List<Train> TrainList = new List<Train>();
            foreach (DataRow dr in dt.Rows)
            {
                TrainList.Add(new Train(Convert.ToInt32(dr["id"])));
            }
            return TrainList;
        }

        public static List<Train> AllTrains()
        {
            return GetTrainListFromSQL("SELECT * FROM trains WHERE deleted = 0 ORDER BY tt_time DESC");
        }

Is there a way where I can call just one common static function where I can pass any of my objects (maybe with a common interface) so that I can simply convert a database to a list<t> without having to clone the code and just change the type reference each time? I.e I have exactly the same method in my WebPage object called:

private static List<WebPage> GetWebPageListFromSQL(string sql)
        {
            DataTable dt = DB.GetTable(sql);
            List<WebPage> WebPageList = new List<WebPage>();
            foreach (DataRow dr in dt.Rows)
            {
                WebPageList.Add(new WebPage(Convert.ToInt32(dr["id"])));
            }
            return WebPageList;
        }


Thanks in advance!
0
Comment
Question by:terryatnexus
  • 5
  • 3
11 Comments
 
LVL 44

Accepted Solution

by:
AndyAinscow earned 334 total points
ID: 38787869
I think the following is basically what you mean
        private static List<T> foo<T>()   //function that accepts generics, returns a list of generics
        {
            return new List<T>();
        }

//example of how to call the function
        private void x()
        {
            List<int> l = foo<int>(); 

Open in new window



You would need to add you SQL code, I did the above for brevity to show how it works
0
 

Author Comment

by:terryatnexus
ID: 38787943
That's really helpful thank you. I've got 95% the way there, I just have 1 problem with line that contains:

GenericList.Add(new typeof<T>(Convert.ToInt32(dr["id"])));


How do I create an instance of that type in order to add it to the list?

My New Code:

        private static List<T> GetListFromSQL<T>(string sql)   //function that accepts generics, returns a list of generics
        {
            DataTable dt = DB.GetTable(sql);
            List<T> GenericList = new List<T>();
            foreach (DataRow dr in dt.Rows)
            {
                GenericList.Add(new typeof<T>(Convert.ToInt32(dr["id"])));
            }

            return GenericList;
        }

        public static List<Train> AllTrains()
        {
            return GetListFromSQL<Train>("SELECT * FROM trains WHERE deleted = 0 ORDER BY tt_time DESC");
        }

Open in new window

0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 38788003
        private static List<T> foo<T>() where T : new()  //requires T supports new
        {
            List<T> l = new List<T>();
            l.Add(new T());
            return l;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            List<int> l = foo<int>();

Open in new window

0
Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

 

Author Comment

by:terryatnexus
ID: 38788015
Almost there - I need to pass the int in to the new() constructor - I currently get:

'T': cannot provide arguments when creating an instance of a variable

How can I pass the int in to the constructor?
0
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 166 total points
ID: 38788415
Change:

GenericList.Add(new typeof<T>(Convert.ToInt32(dr["id"])));

to:

GenericList.Add(new T(Convert.ToInt32(dr["id"])));

Open in new window


You cannot use new and typeof in the manner you are attempting.
0
 
LVL 44

Assisted Solution

by:AndyAinscow
AndyAinscow earned 334 total points
ID: 38788809
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        public abstract class MyBaseClass
        {
            public abstract void SetVal(int i);
        }

        public class MyClass : MyBaseClass
        {
            public int somevar;

            public MyClass() {}
            public override void SetVal(int i) { somevar = i; }
        }


        private  List<T> foo<T>() where T : MyBaseClass, new()
        {
            List<T> l = new List<T>();
            T x = new T();
            x.SetVal(42);
            l.Add(x);
            return l;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            List<MyClass> l = foo<MyClass>(); 
            
        }
    }
}

Open in new window



This is actually a quite complex looking thing - unfortunately I don't know an easier way.  (C'tors with parameters aren't allowed in generic methods apparently).

I've created a base abstract class to define a method - which is used to fill the actual generic object.  The generic method uses a generic which is of this type (you could use an interface instead - it might be better to do so).  So construction is two step: new followed by filling the empty object.
0
 

Author Comment

by:terryatnexus
ID: 38792138
I've managed to come up with my own working solution:

I've changed type T to an Interface that sets out the requirments for the method.

    public static List<IWebCoreObject> GetListFromSQL<IWebCoreObject>(string sql) where IWebCoreObject : new()
    {
        DataTable dt = DB.GetTable(sql);
        List<IWebCoreObject> GenericList = new List<IWebCoreObject>();
        foreach (DataRow dr in dt.Rows)
        {
            Type classType = typeof(IWebCoreObject);
            ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { Convert.ToInt32(dr["id"]).GetType() });
            IWebCoreObject classInstance = (IWebCoreObject)classConstructor.Invoke(new object[] { Convert.ToInt32(dr["id"]) });
            GenericList.Add(classInstance);
        }
        return GenericList;
    }

Open in new window

0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 41682841
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 41682844
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
bound data table problem 2 33
FInd Image Control Gridview 3 21
IEnumerable<T> to a List<T> 8 37
I need help adding validation to my MVC.Net view 6 7
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
This article aims to explain the working of CircularLogArchiver. This tool was designed to solve the buildup of log file in cases where systems do not support circular logging or where circular logging is not enabled
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

860 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question