Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor on type not found

Exception Message: Constructor on type StateLog not found.

I have the following code that does not work for only one class:

        List<T> list = new List<T>();         string line;         string[] lines;          HttpWebResponse resp = (HttpWebResponse)HttpWebRequest.Create(requestURL).GetResponse();          using (var reader = new StreamReader(resp.GetResponseStream()))         {             while ((line = reader.ReadLine()) != null)             {                 lines = line.Split(splitParams);                 list.Add((T)Activator.CreateInstance(typeof(T), lines));             }         } 

The constructor for the class that it does not work for is exactly like the other classes for which it works. The only difference is that this class will be passed 16 arguments instead of 2-5. The constructor looks as such:

    public StateLog(string[] line)     {         try         {             SessionID = long.Parse(line[0]);             AgentNumber = int.Parse(line[1]);             StateIndex = int.Parse(line[5]);             ....         }         catch (ArgumentNullException anex)         {             ....         }     } 

Like I said, it works for the other 5 classes that use this, the only difference is the number of inputs.

like image 956
Jacob Lambert Avatar asked Aug 29 '14 23:08

Jacob Lambert


1 Answers

That's because you are using the Activator.CreateInstance overload which accepts an object array, which is supposed to contain a list of constructor parameters. In other words, it's trying to find a StateLog constructor overload which has 16 parameters, instead of one. This compiles due to array covariance.

So when the compiler sees this expression:

Activator.CreateInstance(typeof(T), lines) 

since lines is a string[], it presumes you want to rely on covariance to have it cast it to object[] automatically, meaning that the compiler actually sees it like this:

Activator.CreateInstance(typeof(T), (object[])lines) 

The method will then try to find a constructor which has a number of parameters equal to lines.Length, all of type string.

For example, if you have these constructors:

class StateLog {       public StateLog(string[] line) { ... }       public StateLog(string a, string b, string c) { ... } } 

Calling Activator.CreateInstance(typeof(StateLog), new string[] { "a", "b", "c" }) will call the second constructor (the one with three parameters), instead of the first one.

What you actually want is to pass the entire lines array as the first array item, effectively:

var parameters = new object[1]; parameters[0] = lines; Activator.CreateInstance(typeof(T), parameters) 

Of course, you can simply use an inline array initializer:

list.Add((T)Activator.CreateInstance(typeof(T), new object[] { lines })); 
like image 130
Groo Avatar answered Sep 30 '22 00:09

Groo