1

Is there some way to get a java List<?> in C#?

I need to get a IEnumerable<T>, where T can be either a class (string), or a struct (int, double...).

public interface I
{
    IEnumerable<object> Enumers { get; }
}

public class A<T> : I
{
    IEnumerable<T> ts;

    public IEnumerable<object> Enumers
    {
        get { return (IEnumerable<object>)this.ts; }
    }
}

public class Test
{
    public static void Main()
    {
        A<double> a = new A<double>();
        var x = a.Enumers;  //It crashes here.
    }
}

It crashes at runtime, since it's not possible to cast from IEnumerable<T> to IEnumerable<object>.

Any ideas?

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
Jordi
  • 20,868
  • 39
  • 149
  • 333
  • 2
    What are you trying to get this code to do? There may be a better c# alternative altogether. – Sayse Jun 08 '16 at 13:25
  • Classes and structs are very different beasts (reference and value semantics). Mixing them in the same collection sounds problematic. – TrueWill Jun 08 '16 at 13:25
  • you would need to add an explicit cast for your `var x = a.Enumers;` line... could use Linq – jleach Jun 08 '16 at 13:25
  • Related, possible duplicate: [Is there an “anonymous” generic tag in C#, like '?' in Java?](http://stackoverflow.com/q/116830/464709) – Frédéric Hamidi Jun 08 '16 at 13:26
  • 2
    `get { return this.ts.Cast(); }` this would give you back the IEnumerable but I'm not sure what you'd want that. – asawyer Jun 08 '16 at 13:27
  • Why do you want to use generics in a way that throws away all that is generic about generics? C# doesn't have anything like `List>` because C# actually has both compile-time and runtime type safety on generics unlike Java where `List` simply becomes `List`, always). – Luaan Jun 08 '16 at 13:29
  • What about cast between `structs` to `object`? If `ts` is `IEnumerable`, what would be the result of `this.ts.Cast()`? – Jordi Jun 08 '16 at 13:29
  • 1
    Yes, your real problem resides in what you are trying to accomplish, not trying to reproduce bad coding practice in a different language :/ –  Jun 08 '16 at 13:32
  • Why not define interface I with IEnumerable Enumers ? and avoid casting at all – Aleksey L. Jun 08 '16 at 13:33
  • Just one point, if that's the code you're actually using, then you don't initialize `Enumers` anywhere. – Barry O'Kane Jun 08 '16 at 13:35
  • @BarryO'Kane It's not, he wouldn't get the exception if he is casting `null` – Manfred Radlwimmer Jun 08 '16 at 13:43

5 Answers5

2

You need to get a different IEnumerable whose elements have been cast like so:

IEnumerable<object> Enumers
{
    get { return this.ts.Cast<object>(); }
}

In C# there is something called boxing which I guess is how this will work for T being structs, though I didn't check.

2

IEnumerable<T> inherits from IEnumerable, so depending on what you actually need, you have two options: Change your return type to IEnumerable

IEnumerable Enumers { get; }

Or cast all elements of your collection to object

public IEnumerable<object> Enumers
{
    get { return ts.Cast<object>(); }
}
Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
0

There is no wildcard <?> in C# like in Java.

But with the usage of dynamic and language specific stuff you are also able to handle such problems: see (C# Generics: wildcards)

Like other user pointed out you can use the Cast functionality for solving your problem.

public IEnumerable<object> Enumers
{
    get { return ts.Cast<object>(); }
}
Community
  • 1
  • 1
wake-0
  • 3,918
  • 5
  • 28
  • 45
0

In the .NET CLR, type parameters are handled very differently depending on whether it's a reference type (e.g. object) or a value type (e.g. double). Essentially, all referene type variables are pointers of the same size, while all value type variables are exactly the size of the value type.

In fact, the CLR will generate a single runtime type applicable for all reference types you can specify for a type parameter, but individual runtime types for every value type you use as the type parameter.

In Java there is no such thing as generics for primitive types, while in .NET there's no such thing as an explicitly boxed version of a value type. Java has double (primitive type) and Double (reference type), but C# only has double (value type). The only way to store a value type as reference is to use the type object or an interface type the particular value type implements.

Wormbo
  • 4,978
  • 2
  • 21
  • 41
0

In case if you can modify your interface I, I would recommend you to do this:

public interface I<T>
{
    IEnumerable<T> Enumers { get; }
}

because of boxing. If not, you can do this:

public class A<T> : I
{
     IEnumerable<T> items;

     public IEnumerable<object> Enumers
     {
         get
         {
            foreach(var item in items)
            {
                yield return (object)item;
            }
         }
     }
}
kagetoki
  • 4,339
  • 3
  • 14
  • 17