9

I've IEnumerable<object> type variable.

IEnumerable<object> items= new object[] { 1, 2, 3 };

What's the best way to check if it's IEnumerable<int>?

I tried

typeof(IEnumerable<int>).IsAssignableFrom(items.GetType())
typeof(IEnumerable<int>).IsInstanceOfType(items)
items is IEnumerable<int>

But, Re-Sharper complains about them all.

In my case, IEnumerable<object> items is of type IEnumerable<int> in most cases. And I wanted to carry out something when it's of type IEnumerable<int> and something else for other types.

ANewGuyInTown
  • 5,957
  • 5
  • 33
  • 45
  • 4
    Each element in `items` can be of any type, so you have to check each element individually. The check you do now only apply to *types* not to content. – Gert Arnold May 27 '15 at 06:52
  • 3
    What is it you are trying to achieve? I'd imagine the easiest would be `valueA.All(item => item is int)` but sounds more like an xy problem – Sayse May 27 '15 at 06:52
  • IEnumerable is the `IEnumerable` in most cases, I wanted to do something when it's of type `IEnumerable` and something else for other types. – ANewGuyInTown May 27 '15 at 06:58
  • @ANewGuyInTown an IEnumerable can contain both strings and ints at the same time. There is no inheritance relationship or meaningful cast from it to a strongly-typed type – Panagiotis Kanavos May 27 '15 at 07:01
  • 1
    `IEnumerable` is never `IEnumerable`. It's never assignable from or to `IEnumerable` (because `int` is a value type and doesn't take part in variance) and if it was `new object[]{1, 2, 3}` would still not be an example of `IEnumerable` since there is nothing to stop you doing `items[1] = "foo"`. – Jon Hanna May 27 '15 at 11:51

4 Answers4

12

If you want to check if an IEnumerable<object> contains only ints, you can use Enumerable.All:

var isInts = items.All(x => x is int);
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • 1
    So, this will loop through all the values in the `items` and check it's type. I was looking for more "out of the box" solution, but I might be expecting too much. Thanks for your answer. I might have to resort to this one. – ANewGuyInTown May 27 '15 at 07:15
  • 1
    @ANewGuyInTown If you know *for sure* that all items are of the same type, you can use `Any` - it will stop after the first iteration. – Gert Arnold May 27 '15 at 07:38
  • @GertArnold But that whole point is that he *doesn't* know :) – Yuval Itzchakov May 27 '15 at 07:42
  • It could be known because of business logic. It's likely that the preceding processes always return IEnumerables of identical types. – Gert Arnold May 27 '15 at 07:44
  • 1
    @GertArnold you might be right. It depends on the situation though. It's `safe` to check `All`, but at the same time not as quick as `Any`. Since, I'm writing it inside a `helper` method which would be using by number of _consumers_, I think I might have to go with the `safe`. – ANewGuyInTown May 27 '15 at 07:56
6

Because Valuetypes do not support co or contravariance. IEnumerable<object> cannot be an IEnumerable<int> - you proved it by yourself because you had to use a cast to produce your IEnumerable<object>, which actually boxed all int values. R# is therefore correctly reporting a suspicious typecheck because it derives from your actions that your checks will always return false.

So in the end you would require to check each element individually if it is an int before you use a cast or you will run into an exception.

Community
  • 1
  • 1
Marwie
  • 3,177
  • 3
  • 28
  • 49
4

You can use Cast Or OfType like this:

Just should care of:

OfType: Return only the elements of type x.

Cast: Will try to cast all the elements into type x. if some of them are not from this type you will get InvalidCastException

items.Cast<int>();

or

items.OfType<int>();
Peyman
  • 3,068
  • 1
  • 18
  • 32
  • 1
    Note: Of type isn't necessarily going to return the same list, and although this answers the title, it doesn't answer the question. – Sayse May 27 '15 at 06:49
  • I don't want to `cast` to a different list/enumerable , I just want to `check` – ANewGuyInTown May 27 '15 at 06:50
  • 1
    @ANewGuyInTown the check makes no sense. You defined a variable that can contain anything - both strings and ints. There is no type or inheritance relationship between this an IEnumerable – Panagiotis Kanavos May 27 '15 at 06:57
1

You can not cast one generic to another, just because the type is a base class of the other. So there is no chance to get an Enumerable<int> from an Enumerable<object>. Re-Sharper complains because the expressions won't return true ever.

you have

IEnumerable<object> items= ((IEnumerable)valueA).Cast<object>();

Perhaps you know that your valueA is filled with integers, but you are allowed to put strings or floats in your items also. So the compiler cannot know for sure that the list is a enumerable of integers.

So you have to create a new enumerable, like Peyman answered before (which is not a new list, just another enumerable):

items.OfType<int>();

this will return only the elements which are integers and ensures that you can get a Enumerable<int>

Herm
  • 2,956
  • 19
  • 32