0

I am having four different Datatypes, all as Lists:

List<DataRowTenant> tenantlist;
List<DataRowOwner> ownerlist;
List<DataRowCustomer> customerlist;
List<DataRowHWDevice> hwdevicelist;
List<DataRowHWCategory> hwcategorslist;

And i want to be able to export them into a CSV. Currently i copied my CSV-export Function five times, just with a different name and parameter definition. So, i was asking myself if i can somehow identify the Datatype of a variable and pass that also in the function?

i already tried the approaches in this Thread, but i couldn't get it to work.

my CSV-Export function is as follows:

    public static void ExportOwnerCSV(List<DataRowOwner> list)
    {
        string columnNames = "";
        string[] outputCsv = new string[list.Count + 1];

        if (list.Count > 0)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "CSV (*.csv)|*.csv";
            sfd.FileName = "Output.csv";
            bool fileError = false;
            bool? result = sfd.ShowDialog();
            if (result == true)
            {
                if (File.Exists(sfd.FileName))
                {
                    try
                    {
                        File.Delete(sfd.FileName);
                    }
                    catch (IOException ex)
                    {
                        fileError = true;
                        MessageBox.Show("It wasn't possible to write the data to the disk." + ex.Message);
                    }
                }
                if (!fileError)
                {
                    try
                    {
                        //var columnCount = DataRowOwner.GetType().GetFields();
                        var list_single = list[0];
                        var columnCount = list_single.GetType().GetProperties(BindingFlags.DeclaredOnly |
                                                                                    BindingFlags.Public |
                                                                                    BindingFlags.Instance);

                        //Header schreiben
                        foreach (PropertyInfo item in columnCount)
                        {
                            outputCsv[0] += "\"" + item.Name + "\"" + ",";
                        }

                        //Body schreiben
                        int row = 1;
                        foreach (var DataRowitem in list)
                        {
                            foreach (PropertyInfo item in columnCount)
                            {
                                outputCsv[row] += "\"" + item.GetValue(list[row - 1]) + "\"" + ",";
                            }
                            row++;
                        }

                        File.WriteAllLines(sfd.FileName, outputCsv, Encoding.UTF8);
                        MessageBox.Show("Data Exported Successfully!", "Info");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error :" + ex.Message);
                    }
                }
            }
        }
        else
        {
            MessageBox.Show("No Record To Export!", "Info");
        }
    }

thanks, any suggestions are appreciated.

Chessmate
  • 61
  • 9
  • 4
    `public static void ExportAnyCSV(IList list)` should work with the code in the method body. There is no need to pass the element type, since you are already using reflection. – Clemens Jul 27 '22 at 12:06
  • Create a base class they all inherit and use that as the parameter – GH DevOps Jul 27 '22 at 12:25
  • This problem is already solved by libraries like CsvHelper. These libraries *cache* the type information so they don't have to rediscover it every time – Panagiotis Kanavos Jul 27 '22 at 12:26

1 Answers1

1

You can declare the function as a generic function, where the type argument of the function is used as the type argument of the list parameter like so:

public static void ExportOwnerCSV<T>(IList<T> list)
{
...
}
lee-m
  • 2,269
  • 17
  • 29
  • 2
    But why generic when IList would already work? It should at least be `IList`. – Clemens Jul 27 '22 at 12:10
  • Both approaches work! But the IList from @Clemens is more intuitive (at least for me) – Chessmate Jul 27 '22 at 12:13
  • 2
    And more flexible. With `IList` or `IList` you can pass any collection type that implements the interface, e.g. ObservableCollection. – Clemens Jul 27 '22 at 12:15
  • 1
    Not really because without the `T` one would have to retrieve the first element just to determine the type. This would fail with empty lists. `typeof(T)` works always – Panagiotis Kanavos Jul 27 '22 at 12:26
  • @PanagiotisKanavos That's true. It should then read `var properties = typeof(T).GetProperties(...)` - not `columnCount`. – Clemens Jul 27 '22 at 12:32
  • A generic function here rather than a non-generic one with an untyped `IList` is what I would personally do here. Yes, you can get away with just an `IList` but throwing away type information like that feels "off" in some vague, hard-to-articulate way. The function should probably take an `IList` rather than `List` to make it more flexible so will tweak that. – lee-m Jul 27 '22 at 19:04