mardi 22 octobre 2019

Assigning instance variables obtained through reflection in generic method

I have data in tab-separated values (TSV) text files that I want to read and (eventually) store in database tables. With the TSV files, each line contains one record, but in one file the record can have 2 fields, in another file 4 fields, etc. I wrote working code to handle the 2-field records, but I thought this might be a good case for a generic method (or two) rather than writing new methods for each kind of record. However, I have not been able to code this because of 2 problems: I can't create a new object for holding the record data, and I don't know how to use reflection to generically fill the instance variables of my objects.

I looked at several other similar posts, including Datatable to object by using reflection and linq

Below is the code that works (this is in Windows, if that matters) and also the code that doesn't work.

public class TSVFile
{
    public class TSVRec
    {
        public string item1;
        public string item2;
    }

    private string fileName = "";

    public TSVFile(string _fileName)
    {
        fileName = _fileName;
    }

    public TSVRec GetTSVRec(string Line)
    {
        TSVRec rec = new TSVRec();

        int offset = Line.IndexOf('\t');

        try
        {
            string[] fields = Line.Split(new char[1] { '\t' });

            rec.item1 = fields[0];
            rec.item2 = fields[1];
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show("Bad import data on line: " + 
                Line + "\n" + ex.Message, "Error",
                System.Windows.Forms.MessageBoxButtons.OK,
                System.Windows.Forms.MessageBoxIcon.Error);
        }

        return rec;
    }

    public List<TSVRec> ImportTSVRec()
    {
        List<TSVRec> loadedData = new List<TSVRec>();
        using (StreamReader sr = File.OpenText(fileName))
        {
            string Line = null;
            while ((Line = sr.ReadLine()) != null)
            {
                loadedData.Add(GetTSVRec(Line));
            }
        }

        return loadedData;
    }

    // *** Attempted generic methods ***
    public T GetRec<T>(string Line)
    {
        T rec = new T();  // compile error!
        Type t = typeof(T);

        FieldInfo[] instanceVars = t.GetFields();

        string[] fields = Line.Split(new char[1] { '\t' });

        for (int i = 0; i < instanceVars.Length - 1; i++)
        {
            rec. ??? = fields[i];   // how do I finish this line???
        }

        return rec;
    }

    public List<T> Import<T>(Type t)
    {
        List<T> loadedData = new List<T>();
        using (StreamReader sr = File.OpenText(fileName))
        {
            string Line = null;
            while ((Line = sr.ReadLine()) != null)
            {
                loadedData.Add(GetRec<T>(Line));
            }
        }

        return loadedData;
    }
}

I saw the line T rec = new T(); in the above-mentioned post, but it doesn't work for me...

I would appreciate any suggestions for how to make this work, if possible. I want to learn more about using reflection with generics, so I don't only want to understand how, but also why.





Aucun commentaire:

Enregistrer un commentaire