none
Generic Method in LINQ query RRS feed

  • Question

  • Is it possible to create generic method in LINQ query

    public class Manager

    {

    :

    public DataSet pullRows<T>(string s1)

    {

        IEnumerable<T> qResl = from val in MyTable

                                              where val.Column1=s1

                                              select (o => new T(val))

        :

         return ds;

    }

    }

    ////////

    Tried this option

    var query = from val in MyTbl
                 where val.Price > 9.99
                 select new { val.Price, val.Genre };

    query.CopyToDataTable(table, LoadOption.PreserveChanges);

    but I see compile error

    Error 1 The type 'AnonymousType#1' cannot be used as type parameter 'T' in the generic type or method 'System.Data.DataTableExtensions.CopyToDataTable<T>(System.Collections.Generic.IEnumerable<T>, System.Data.DataTable, System.Data.LoadOption)'. There is no implicit reference conversion from 'AnonymousType#1' to 'System.Data.DataRow'. C:\MSOfficeUtil\Manager.cs 44 13 MSOfficeUtil

    Thanks in advance.

    lb55


    • Edited by lb55 Sunday, March 4, 2018 10:40 PM
    Sunday, March 4, 2018 9:51 PM

All replies

  • I would suggest looking at the source (line 110 and 113) for CopyToDataTable to understand how to write your own.

    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Monday, March 5, 2018 1:28 AM
    Moderator
  • Obviously, you can't do it with a datatable. Your other option is to use a List<T> of custom objects, like a DTO. Linq works better with custom objects not datatables.

    https://www.codeproject.com/Articles/1050468/Data-Transfer-Object-Design-Pattern-in-Csharp

    https://dzone.com/articles/reasons-move-datatables

    Monday, March 5, 2018 2:11 AM
  • Hello lb55,

    The existing CopyToDataTable  methods only operate on an IEnumerable(T) source where the generic parameter T is of type DataRow. Although this is useful, it does not allow tables to be created from a sequence of scalar types, from queries that return anonymous types.

    Here's a link can help you to implement a CopyToDataTable method which can load a table from a sequence of scalar or anonymous types. Please refer to it.

    How to: Implement CopyToDataTable<t>Where the Generic Type T Is Not a DataRow</t>

    If you just want to use CopyToDataTable<t>method, you have to convert IEnumable<T> type whose T is Anonymous type to IEnumable<DataRow> type, maybe you need do something like this.

    ...
    
       DataTable temp = new DataTable();
                var datarows = query.Select(r => {
                    var row = temp.NewRow();
                    row["Price"] = r.Price;
                    row["Genre"] = r.Genre;
                 
                    return row;
                });         
    
                datarows.CopyToDataTable(table, LoadOption.PreserveChanges);
    

    Best regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, March 5, 2018 2:44 AM
    Moderator
  • Thanks for all the pointers. I can adapt any of those options and provide a solution. I think I'm missing generalization.

    publicDataSet pullRows<T>(string s1)(Stringstr1) whereT: new()

    {

     IEnumerable<T> qResl = from val in MyTable

                                              where val.Column1=s1

                                              select (o => { T o1 = new T();

                                                                    // How to set the values in o1 using val attributes?

                                                                    return o1;

                                                                  }

                                                        )

    }

    Thanks  in advance.

    lb55

    Monday, March 5, 2018 5:39 PM
  • Hello lb55,

    >>How to set the values in o1 using val attributes?

    You are using constructor constraint to require generic object has constructor that has empty parameter.

    If you don't add type constraint the compiler just recognize it as object type. you only access object type's fields and methods. So you need to add type constraint.

    1.define base object.

     class Test {
            public string TestField;
        }

    2.put type constraint on generic parameter

      public DataSet pullRows<T>(String str1) where T :Test,new()

    3. You could access TestField by T instance in generic method.

                                                                

    Best regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Proposed as answer by Bob Ding Wednesday, March 7, 2018 8:26 AM
    • Edited by Fei HuModerator Thursday, March 8, 2018 8:54 AM correct the code
    Tuesday, March 6, 2018 6:09 AM
    Moderator
  • Neil,

    I appreciate your time.

    I think it still not the pure generic.

    public DataSet pullRows<T>(String str1) where T : new (string, string, string)

    {

    }

    But I read somewhere that it takes only default () constructor not the parameterized one.

    Looking something like pullRows<Customers>() or pullRows<Products>() etc.

    Thanks

    lb55


    • Edited by lb55 Wednesday, March 7, 2018 3:23 PM
    Wednesday, March 7, 2018 3:19 PM
  • Hello lb55,

    >>But I read somewhere that it takes only default () constructor not the parameterized one.

    Yes, the only constructor constraint you can specify is for a no-arg constructor. As for a workaround, you could pass a delegate that can create objects of type T. A simple test like below.

    class Test
        {
            public string TestField;
            public Test(string s1) { }
        }
        class Program
        {
            public void pullRows<T>(String str,Func<string,T> func)where T:Test{
    
                T t = func(str);
                t.TestField = "T";
                      
            }
            static void Main(string[] args)
            {
                Program p = new Program();
    
                p.pullRows<Test>("T1", (str) => new Test(str));
            }

    If you have any issues, Please feel free to contact me. I'm pleasure to help you.

    Best regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, March 8, 2018 9:36 AM
    Moderator