简体   繁体   中英

Switch case in for loop in C#

I am reading from an excel row by row.The individual column headers are at 2nd row . But the data start from the 4th row itself . I want to first check for the column headers and put the value from the 4th rows respectively to the associated model properties .

在此输入图像描述

So I wanted to use a case statement inside of a for loop instead of a if else check.

But it breaks after first case only . I know it is intended but is there any other better efficient way ?

ListGroupMembershipUploadInput gl = new ListGroupMembershipUploadInput();

for (int rw = 4; rw <= ws.Dimension.End.Row; rw++)
{
    //Dictionary<string, string> groupMembershipUploadDict = new Dictionary<string, string>();

    int headerCol = 2;

    GroupMembershipUploadInput gm = new GroupMembershipUploadInput();

    for (int col = ws.Dimension.Start.Column; col <= ws.Dimension.End.Column; col++)
    {
        string val = ws.Cells[headerCol, col].Value.ToString();

        switch (ws.Cells[headerCol, col].Value.ToString())
        {
            case "Code for the particular Chapter(example,'12345' )" :
                gm.chpt_cd = (ws.Cells[rw, col].Value ?? null).ToString();
                break;
            case "Existing Constituent Master Id" :
                gm.cnst_mstr_id = (ws.Cells[rw, col].Value ?? null).ToString();
                break;
            case "Prefix of the constituent(Mr, Mrs etc)" :
                gm.cnst_prefix_nm = (ws.Cells[rw, col].Value ?? null).ToString();
                break;
            case "First Name of the constituent(Mike)" :
                gm.cnst_first_nm = (ws.Cells[rw, col].Value ?? null).ToString();
                break;
            case "Middle Name of the constituent(R.)" :
                gm.cnst_middle_nm = (ws.Cells[rw, col].Value ?? null).ToString();
                break;
            case "Last Name of the constituent(Andrien)" :
                gm.cnst_last_nm = (ws.Cells[rw, col].Value ?? null).ToString();
                break;
            case "Address Line 1(Home) - (431 Washington Blvd)" :
                gm.cnst_addr1_street1 = (ws.Cells[rw, col].Value ?? null).ToString();
                break;
            }

            gl.GroupMembershipUploadInputList.Add(gm);
        }

    }

And here is the model class I have built.

public class GroupMembershipUploadInput
{

    public string chpt_cd {get;set;}
    public string cnst_mstr_id {get;set;}
    public string cnst_prefix_nm {get;set;}
    public string cnst_first_nm {get;set;}
    public string cnst_middle_nm {get;set;}
    public string cnst_last_nm {get;set;}
    public string cnst_addr1_street1 {get;set;}
}

public class ListGroupMembershipUploadInput
{
    public List<GroupMembershipUploadInput> GroupMembershipUploadInputList { get; set; }
}

So I want to convert the excel data into a list of model objects with the null values also .

You execute

 gl.GroupMembershipUploadInputList.Add(gm);

inside the inner for loop. That means that the object is added after evaluating each column. So the object be be added to the list multiple times.

Move the line that adds the object to the list after the inner for loop.

Also, you do not initialize the property GroupMembershipUploadInputList in the ListGroupMembershipUploadInput class. So it is null and when trying to add the first object to the list, you will get a NullReferenceException .

You need to create the list:

public class ListGroupMembershipUploadInput
{
    public List<GroupMembershipUploadInput> GroupMembershipUploadInputList { get; set; } = new List<GroupMembershipUploadInput>();
}

You need to do something like this to get rid of the switch statement:

ListGroupMembershipUploadInput gl = new ListGroupMembershipUploadInput();

int headerCol = 2;

Dictionary<string, int> map = Enumerable
    .Range(ws.Dimension.Start.Column, ws.Dimension.End.Column - ws.Dimension.Start.Column + 1)
    .ToDictionary(col => ws.Cells[headerCol, col].Value.ToString(), col => col);

for (int rw = 4; rw <= ws.Dimension.End.Row; rw++)
{
    gl.GroupMembershipUploadInputList.Add(new GroupMembershipUploadInput()
    {
        chpt_cd = ws.Cells[rw, map["Code for the particular Chapter(example,'12345' )"]].Value.ToString(),
        cnst_mstr_id = ws.Cells[rw, map["Existing Constituent Master Id"]].Value.ToString(),
        cnst_prefix_nm = ws.Cells[rw, map["Prefix of the constituent(Mr, Mrs etc)"]].Value.ToString(),
        cnst_first_nm = ws.Cells[rw, map["First Name of the constituent(Mike)"]].Value.ToString(),
        cnst_middle_nm = ws.Cells[rw, map["Middle Name of the constituent(R.)"]].Value.ToString(),
        cnst_last_nm = ws.Cells[rw, map["Last Name of the constituent(Andrien)"]].Value.ToString(),
        cnst_addr1_street1 = ws.Cells[rw, map["Address Line 1(Home) - (431 Washington Blvd)"]].Value.ToString(),
    });
}

This effectively moves the gl.GroupMembershipUploadInputList.Add(gm); outside of the inner for loop.

It also makes your code much smaller and easier to read.

Answering you question "is there any other better efficient way?"

1) If you want to use Office Interop, reading cell by cell is not most efficient way. There one less obvious way people often don't know about.

This will return two-dimensional array in one go then you just loop through with for cycle. You will still need to manually skip 2nd row, nulls and handle conversion. But this will be much faster and cleaner:

Worksheets("Sheet1").Range("A1:D10").Value

2) Most efficient way is to use OleDB, then you don't need Office installed, just free component Microsoft Access Database Engine 2010 Redistributable (note : there are x86 and x64 versions, must mach your app)

Below is code draft/snippet I compiled, most likely will not work, but these are maine peaces involved. The idea is that you work with data from excel like with database and tables. Best part is that you get IDataReader therefore you read rows one by one and without loading all into memory, so besides speed this is also RAM-wise.

private IDataReader OpenReader()
{
    _strConn = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;HDR={1};IMEX=1;TypeGuessRows=0;ImportMixedTypes=Text\"",
                                _fileName, Configuration.HasHeaders ? "Yes" : "No");

    conn = new OleDbConnection(_strConn);
    conn.Open();

    var schemaTable = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
    string sheet = schemaTable.Rows[0]["TABLE_NAME"].ToString();
    var schemaTableColumns = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, sheet, null });

    // I am taking 1-st sheet here for simplicity
    string sheetName = schemaTable
      .Rows[0]["TABLE_NAME"].ToString();

    var cmd = new OleDbCommand(String.Format("SELECT * FROM [{0}]", sheetName), conn);

    cmd.CommandType = CommandType.Text;

    return cmd
       .ExecuteReader(CommandBehavior.Default);
}

PS. I you decide to pursue last option I can give you more info here if needed.

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