?
Solved

Dynamically Typed List

Posted on 2013-01-17
11
Medium Priority
?
46 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
9 Comments
 
LVL 45

Accepted Solution

by:
AndyAinscow earned 1336 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 45

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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 

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 664 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 45

Assisted Solution

by:AndyAinscow
AndyAinscow earned 1336 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 45

Expert Comment

by:AndyAinscow
ID: 41682841
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 41682844
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
High user turnover can cause old/redundant user data to consume valuable space. UserResourceCleanup was developed to address this by automatically deleting user folders when the user account is deleted.
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…
This lesson discusses how to use a Mainform + Subforms in Microsoft Access to find and enter data for payments on orders. The sample data comes from a custom shop that builds and sells movable storage structures that are delivered to your property. …
Suggested Courses

809 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