0

I have a list of objects (their types are unknown ahead of time). The example below shows hard coded values, but my actual code populates the args list by reading from a CSV file. I then want to pass this list of args to a typical method that asks for certain parameters. So I cast the elements to the required types as shown. I'm getting error:

Specified cast is not valid

when the method is called at run time. How should I go about accomplishing this?

var args = new List<object>();
        args.Add(5495);
        args.Add("String1");
        args.Add(10133);
        args.Add("String2");

        result = request.GetCustomer((long) args[0], (string) args[1], (int) args[2], (string) args[3]);
Mike Debela
  • 1,930
  • 3
  • 18
  • 32
AngieM
  • 735
  • 6
  • 27
  • 1
    The error is specifically telling you why you can't perform the cast, including what the actual type of the object is and what you're trying to cast it to. You'll need to cast the object to its *actual* type, if you want it to not fail at runtime. – Servy Jun 13 '16 at 13:25
  • Well, a good start would be a try catch block around this and a count so that you can see which row in your csv is the culprit. – Kell Jun 13 '16 at 13:25
  • @Kell A `try`/`catch` block would just obscure the problem. He can already see the error, he merely needs to fix the bug in his code. – Servy Jun 13 '16 at 13:27
  • you'll want to safe cast these values, so `args[0] as long` – Callum Linington Jun 13 '16 at 13:27
  • @Servy The bug might be in the data passed to the code from the csv file. – Kell Jun 13 '16 at 13:29
  • @CallumLinington That would in no way fix the problem, it would just result in the code not working but without throwing. – Servy Jun 13 '16 at 13:29
  • @Kell If so, then he'd need to fix that bug. Either way, he knows exactly what the problem is. – Servy Jun 13 '16 at 13:29
  • @CallumLinington `args[0] as long` won't even compile. – Dirk Jun 13 '16 at 13:30
  • You can find some additional information why your case fails in https://stackoverflow.com/questions/3541680/strange-casting-behaviour-cannot-cast-object-int-to-long – Dirk Jun 13 '16 at 13:30

5 Answers5

4

When you add value types to List<object>(),

args.Add(5495);

the item will be Boxed. The above line causes 5495 to be boxed from int. To unbox, you need to explicitly cast args[0] to its type as - (int)args[0]. So, if your method is accepting long as its first parameter, do (long)(int)args[0]. You unboxed args[0] and then cast the value to long.

Mike Debela
  • 1,930
  • 3
  • 18
  • 32
  • 1
    Thank you!!! This fixed the problem, and I actually realized that I could just cast that parameter as (int) rather than (long). – AngieM Jun 13 '16 at 17:57
1

The problem is that 5495 will have a type of int and you are trying to cast it to a long. You can get round this in several ways, here is one of them;

Replace this;

(long) args[0]

with this;

(long) (int) args[0]

This wouldn't be a very useful solution however since you could never actually pass your method a long value, instead you can do this;

args.Add((long) 5495);
mark_h
  • 5,233
  • 4
  • 36
  • 52
0

try using Convert.ChangeType

      var args = new List<object>();
        args.Add(5495);
        args.Add("String1");
        args.Add(10133);
        args.Add("String2");


        long aLong = (long)Convert.ChangeType(args[0], typeof(long), CultureInfo.InvariantCulture);

        string aStr = (string)Convert.ChangeType(args[1], typeof(string), CultureInfo.InvariantCulture);

        int aInt = (int)Convert.ChangeType(args[2], typeof(int), CultureInfo.InvariantCulture);
Amit Pore
  • 127
  • 3
  • 13
0

create separate class for store list data

class Test{

private long Variable1{get;set;}

private string Variable2{get;set;}

private long Variable3{get;set;}

private string Variable4{get;set;}

}

var args=new List();

var obj=new Test{

Variable1=5495,

Variable2="String1",

Variable3=10133,

Variable4="String2"

}

args.add(obj);

result=request.GetCustomer(args[0].Variable1,args[0].Variable2,args[0].Variable3,args[0].Variable4);

0

Let's simplify the problem a bit.

var args = new List<object>();
args.Add(5495);
var l = (long)args[0]; // throws an exception

What exactly is inside args[0]? An int (because 5495 is an int to the compiler, if you want it to be a long, type 5495L). More precisely, a boxed int, because you had to store it in a reference-type storage location. A boxed struct can only be unboxed to the same struct or to a nullable of this struct. In our case

var i = (int)args[0];
var nullable = (Nullable<int>)args[0];
var nullable1 == (int?)args[0];

would all work fine.

You can cast the value to anything it's compatible with after you've unboxed it though.

You can read more about boxing and unboxing on msdn. It's a very precious understanding if you want to use C# efficiently.

The root cause of your problem is you're using a List<object> though, making the boxing unavoidable. It's pretty rare you really need to do that, you should probably think your architecture over to avoid it.

Falanwe
  • 4,636
  • 22
  • 37
  • Thanks for the recommended reading on boxing/unboxing (especially on the performance). I am such a noob. Yes this design is probably not ideal. I was having to call different methods with 20-30 parameters for each of them, so I was tired of defining 20-30 variables for each method --> list of objects. I'm all ears if you have a better recommendation for my situation. Thanks! – AngieM Jun 13 '16 at 17:53
  • 20-30 parameters is *a lot*. Any sane method should probably not have that much. You should probably refactor most of those in some custom classes that makes sense in your business logic, and pass a couple of these objects to your method. – Falanwe Jun 13 '16 at 19:55
  • These are mostly web service methods that create certain types of data (e.g. a company's record with lots of data about the company). Yes as I go along I'll probably refactor some common fields. – AngieM Jun 14 '16 at 01:12