2

So I have a method in my code where one of the parameters is a IEnumerable<object>. For clarity purposes, that will be the only parameter for the example. I was originally calling it with a variable that was a List<string>, but then realized I only needed those to be chars and changed the signature of the variable to List<char>. Then I received an error in my program saying:

Cannot convert source type 'System.Collections.Generic.List<char>'
to target type 'System.Collections.Generic.IEnumerable<object>'.

In code:

// This is the example of my method
private void ConversionExample(IEnumerable<object> objs)
{
    ...
}

// here is another method that will call this method.
private void OtherMethod()
{
    var strings = new List<string>();
    // This call works fine
    ConversionExample(strings);

    var chars = new List<char>();
    // This will blow up
    ConverstionExample(chars);
}

The only reason that I could possibly think of as to why the first will work, but the second won't is because a List<char>() is convertible to a string? I don't really think that would be it, but that's the only long-shot guess that I can make about why this doesn't work.

Dmitry
  • 13,797
  • 6
  • 32
  • 48
krillgar
  • 12,596
  • 6
  • 50
  • 86
  • 3
    a char is not an Object, a String is – pm100 Apr 17 '15 at 16:12
  • 3
    @pm100 in c# isnt't basically everything an object? – LuckyLikey Apr 17 '15 at 16:15
  • @LuckyLikey: Everything is treated as an object, but in fact not everything is an object; the compiler boxes and unboxes value types for you, so that they look like objects. – Solal Pirelli Apr 17 '15 at 16:21
  • @SolalPirelli thank's that's why I didn't find an inheritance between those two types. – LuckyLikey Apr 17 '15 at 16:25
  • 1
    @LuckyLikey `char` inherits from `ValueType` which inherits from `object`, so in fact a `char` *is* an `object`. [Read this for more info](http://stackoverflow.com/questions/1682231/how-do-valuetypes-derive-from-object-referencetype-and-still-be-valuetypes/1682604#1682604) – Servy Apr 17 '15 at 16:26
  • @Servy Ok, your *Read more* link clarified for me, why yours and SlalPirellis Statement do not conflict. Thanks alot. – LuckyLikey Apr 17 '15 at 16:30
  • @pm100 Value type *do* derive from `object`. See the linked post written by someone who, at the time he wrote the post, was a principle dev of the C# compiler. – Servy Apr 17 '15 at 16:30
  • 1
    yup - char is Object, but not in the List<> case. I learned something – pm100 Apr 17 '15 at 16:32
  • 1
    Related question: [Why covariance and contravariance do not support value type](http://stackoverflow.com/q/12454794/3052062) – chomba Apr 17 '15 at 16:42
  • Thanks for that, @chomba. I'd been searching for an answer to this since yesterday, and still hadn't found anything. I knew there had to be an answer here somewhere, and most likely that Jon Skeet had answered it. – krillgar Apr 17 '15 at 17:18

2 Answers2

6

Generic argument covariance doesn't support value types; it only works when the generic argument is a reference type.

You can either make ConversionExample generic and accept an IEnumerable<T> rather than an IEnumerable<object>, or use Cast<object> to convert the List<char> to an IEnumerable<object>.

Servy
  • 202,030
  • 26
  • 332
  • 449
0

This would be my solution:

// This is the example of my method
private void ConversionExample<T>(IEnumerable<T> objs)
{
    ...
}

// here is another method that will call this method.
private void OtherMethod()
{
    var strings = new List<string>();
    // This call works fine
    ConversionExample<string>(strings);

    var chars = new List<char>();
    // This should work now
    ConversionExample<char>(chars);
}
Ron Beyer
  • 11,003
  • 1
  • 19
  • 37
  • 3
    That's pretty cool, but it doesnt really answer why `List` works and `List` doesn't which was the question if I understanded it correctly – LuckyLikey Apr 17 '15 at 16:22
  • @LuckyLikey, the other answer sums it up pretty well. Primitive types are not objects (they can be boxed INTO objects, but they do not derive from objects), so without explicitly boxing the compiler can't infer that you want to implicitly box a primitive type into the object type. – Ron Beyer Apr 17 '15 at 16:24
  • Yes, you are right, my comment should be deleted :) – LuckyLikey Apr 17 '15 at 16:27
  • 2
    @RonBeyer That is wrong. First, C# has no concept of the term "primitive type". Second, value types (which I assume is what you meant?) *are* objects, and they *do* derive from objects. The only types in C# that don't derive from `object` are pointers, to which aren't involved in this case. – Servy Apr 17 '15 at 16:29
  • 1
    @servy https://msdn.microsoft.com/en-us/library/aa711900%28v=vs.71%29.aspx pretty explicitly defines primitive types. I did misunderstand something though, yes these types are derived from objects but are not treated as objects until they are explicitly boxed into objects. This is very evident by not being able to assign them to null unless they are boxed first. – Ron Beyer Apr 17 '15 at 16:33
  • @RonBeyer Look at the section; that's defining primitives **in the context of VB.NET**. VB defines the term "primitive types"; C# does not. C# defines nullabilty of objects; there are types that are nullable and types that are non-nullable. This definition in no way relies on the usage of the term "primitive type". – Servy Apr 17 '15 at 16:34