Search code examples
c#genericscollectionsgeneric-method

Returning a generic list


I'm trying to return a generic list after loading values from a file. However, after much fiddling with type manipulations I still can't get it to agree with me. The code is below; my questions are:

  1. Do I need to identify every key type like I'm starting to below, or is there a quicker way? I see the 'where T: ...' could be relevant here but I'd like to allow DateTime, int, string, double etc if possible and I can't see how to do those with 'where.'
  2. Why can't I add my DateTime item to the List which is of datetime?
  3. When I try to get the type (listType) this seems to go out of scope. Even when I declare the type in the line above where I use it, it says no such object exists.

Many thanks for your thoughts

public static List<T> FileToGenericList<T>(string FilePath, int ignoreFirstXLines = 0, bool stripQuotes = true)
{
    List<T> output = new List<T>();

    Type listType = output.GetType().GetGenericArguments()[0];

    try
    {
        using (StreamReader stream = new StreamReader(File.Open(FilePath, FileMode.Open)))
        {
            string line;
            int currentLine = 0;

            while ((line = stream.ReadLine()) != null)
            {
                // Skip first x lines
                if (currentLine < ignoreFirstXLines) continue;

                // Remove quotes if needed
                if (stripQuotes == true)
                {
                    line = line.Replace(@"""", @"");
                }

                // Q1 - DO I HAVE TO HAVE THIS FOR EACH TYPE OR IS THERE A QUICKER WAY
                if (listType == typeof(System.DateTime))
                {
                    DateTime val = new System.DateTime();
                    val = DateTime.Parse(line);

                    // Q2 ERROR: 'Argument type is not assignable to parameter type 'T''                    
                    output.Add(val);

                    // For some reason the type 'listType' from above is now out of scope when I try a cast
                    output.Add((listType)val);
                }
                if (listType == typeof(System.String))
                {
                    //DateTime val = new System.DateTime();
                    //val = DateTime.Parse(line);
                    //output.Add(val.ToString());
                }

                // Continue tracking for line skipping purposes
                currentLine++;
            }
        }
    }
    catch (Exception ex)
    {
        throw new Exception("Error - there was a problem reading the file at " + FilePath + ".  Error details: " + ex.Message);
    }    
    return output;
}

Solution

  • // Q1 - DO I HAVE TO HAVE THIS FOR EACH TYPE OR IS THERE A QUICKER WAY

    Here is some test code to get you started:

    using System;
    using System.Collections.Generic;
    
    namespace AddGenericToList
    {
        class Program
        {
            static void Main(string[] args)
            {
                var tc = new ListClass<string>();
    
                tc.Add("a value");
                tc.Add(123);
                tc.Add(DateTime.Now);
            }
        }
    
        internal class ListClass<T>
        {
            private readonly List<T> list = new List<T>();
    
            public void Add(object value)
            {
                list.Add((T)Convert.ChangeType(value, Nullable.GetUnderlyingType(typeof (T)) ?? typeof (T)));
            }
        }
    }
    

    However, invalid casts will throw an error. For instance, DateTime can be converted to string but not to int.