when instantiating an object using a constructor, an exception is thrown in c#: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException

I am trying to instantiate an object using data from an Excel document .
For some reason I’m getting this exception:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ‘The best overloaded method match for ‘TRY.Employee.Employee(double, string, string, double)’ has some invalid arguments’

becouse of this line:

employees.Add(new Employee(ws.Cells[i + 1, 1].Value, ws.Cells[i + 1, 2].Value, ws.Cells[i + 1, 3].Value, ws.Cells[i + 1, 4]));

or this one:

Employee employee = new Employee(ws.Cells[i + 1, 1].Value, ws.Cells[i + 1, 2].Value, ws.Cells[i + 1, 3].Value, ws.Cells[i + 1, 4]);

what could possibly be the problem? I need to be able to add all the rows to my list.

the data is coming in correctly, I checked it using:
Console.WriteLine(ws.Cells[i+1, 3].Value)
the data types of the constructor are valid, I checked that using:
Console.WriteLine(ws.Cells[i + 1, 2].Value.GetType());

my code:

public class Employee
    {
        public double Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public double Age { get; set; }


        public Employee(double id, string firstName, string lastName, double age)
        {
            Id = id;
            FirstName = firstName;
            LastName = lastName;
            Age = age;
        }

    }
`
`        static void ExtractAndTransformData()
        {
            String filePath = "C:\\Users\\Owner\\Desktop\\employee3.xlsx";

            Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();

            Workbook wb;
            Worksheet ws;

            wb = excel.Workbooks.Open(filePath);
            ws = wb.Worksheets[1];

             ws.Columns.ClearFormats();
            ws.Rows.ClearFormats();

            int iTotalColumns = ws.UsedRange.Columns.Count;
            int iTotalRows = ws.UsedRange.Rows.Count;


            List<Employee> employees = new List<Employee>();

            for (int i = 0; i < iTotalRows; i++)
            {
                Employee employee = new Employee(ws.Cells[i + 1, 1].Value, ws.Cells[i + 1, 2].Value, ws.Cells[i + 1, 3].Value, ws.Cells[i + 1, 4]);

                employees.Add(new Employee(ws.Cells[i + 1, 1].Value, ws.Cells[i + 1, 2].Value, ws.Cells[i + 1, 3].Value, ws.Cells[i + 1, 4]));

            }
        }

>Solution :

You’re forcing the runtime to bind to the constructir for every row, and one or more rows is not able to bind to the constructor given the runtime type of the column values. You said you checked the types, but have you checked every row?

A safer method would be to use a cast or type check before binding to the constructor and dealing with any type problrems first:

double id = (double)ws.Cells[i + 1, 1].Value;
string firstName = (string)ws.Cells[i + 1, 2].Value;
string lastName = (string)ws.Cells[i + 1, 3].Value;
double age = (double)ws.Cells[i + 1, 4].Value;
Employee employee = new Employee(id, firstName, lastName, age);

Now any runtime type errors will be thrown when casting to the compile-time type, and you can decide what to do if there are incompatibilities (e.g. blank values).

Another possible performance improvement once you get the type problems fixed is to not call Value for each cell, but read all of the values into a 2-d object array and read the array cell-by-cell (still casting to the appropriate destination type):

But first get the type checking working, then worry about performance if it is a problem.

Leave a Reply