简体   繁体   中英

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();

        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.

I wish @EdPlunkett had posted his suggestion as an answer, rather than a comment, so I could mark it as the answer...

To summarize: to do what I want to do, there is no need for "Assigning instance variables obtained through reflection in generic method". In fact, I can have a generic solution without using a generic method:

public class GenRec
{
    public List<string> items = new List<string>();
}

public GenRec GetRec(string Line)
{
    GenRec rec = new GenRec();

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

        for (int i = 0; i < fields.Length; i++)
            rec.items.Add(fields[i]);
    }
    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<GenRec> Import()
{
    List<GenRec> loadedData = new List<GenRec>();
    using (StreamReader sr = File.OpenText(fileName))
    {
        string Line = null;

        while ((Line = sr.ReadLine()) != null)
            loadedData.Add(GetRec(Line));
    }

    return loadedData;
}

I just tested this, and it works like a charm!

Of course, this isn't helping me to learn how to write generic methods or use reflection, but I'll take it...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM