简体   繁体   中英

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?

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.

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

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

In the .NET CLR, type parameters are handled very differently depending on whether it's a reference type (eg object ) or a value type (eg 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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM