Jordi
Jordi

Reputation: 23207

Java List<?> in C#

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?

Upvotes: 1

Views: 429

Answers (5)

kagetoki
kagetoki

Reputation: 4777

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;
            }
         }
     }
}

Upvotes: 0

Wormbo
Wormbo

Reputation: 4992

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.

Upvotes: 0

wake-0
wake-0

Reputation: 3968

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>(); }
}

Upvotes: 0

Manfred Radlwimmer
Manfred Radlwimmer

Reputation: 13394

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>(); }
}

Upvotes: 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.

Upvotes: 2

Related Questions