C# – Use the Subsonic.Select() ExecuteTypedList Method with String

cgenericssubsonic

This is more a question regarding generics than subsonic:

Imagine if have the following code:

    List<int> result = 
      DB.Select(Product.Columns.Id)
        .From<Product>()
        .ExecuteTypedList<int>();

That works great and returns a generic list with the ids from my Product table.

But if I want to get a list of the ProductName:

    List<String> result = 
      DB.Select(Product.Columns.ProductName)
        .From<Product>()
        .ExecuteTypedList<String>();

it throws a compiler message (translated from german):

"string" has to be a non-abstract type
with a public Constructor without
parameter, in order to be used as a
generic type or in the generic method
"SubSonic.SqlQuery.ExecuteTypedList()"
as param "T".

cause: String has no empty contructor:

int i = new int;       // works
String s = new String; // compiler error: "string" does not contain a constructor that takes '0' argument

If I use a List<Object> instead it works, but is there a more elegant way, where I can use List<String> ?

Update: List<Object> does not work. I indeed get a list of objects but that seem to be "empty" object that doesn't contain my ProductNames ( object.ToString() returns {Object} )

Best Answer

With a little bit dotnet magic it is possible without patching the subsonic code.

  1. Create a new class SubsonicSqlQueryExtensionMethods and drop this code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using SubSonic;
    
    namespace MyUtil.ExtensionMethods
    {
        public static class SubSonicSqlQueryExtensionMethods
        {
            public static List<String> ExecuteTypedList(this SqlQuery qry)
            {
                List<String> list = new List<String>();
                foreach (System.Data.DataRow row in qry.ExecuteDataSet().Tables[0].Rows)
                {
                     list.Add((String)row[0]);
                }
                return list;
            }
        }
    }
    

Now add a reference to MyUtil.ExtensionMethods to your class:

    using MyUtil.ExtensionMethods;

And finally this works:

    List<String> result = DB.Select(User.Columns.Name).From<User>().ExecuteTypedList();

Please note that the above extension method overloads the ExecuteTypedList() method with no type-argument (unfortunately this snippet requires dotnet 3.5, but for me it works)