29

I am looking for a one liner that transforms List<T> into object[]. It's one liner, so I am not interested in solutions such as foreach, or for...

Any takers?

Hint: No, both List<T>.ToArray() and List<T>.ToArray<object>() don't work.

Edit: Why List<T>.ToArray<object>() doesn't work? Because it can't compile.

jv42
  • 8,521
  • 5
  • 40
  • 64
Graviton
  • 81,782
  • 146
  • 424
  • 602
  • Why don't List.ToArray() and List.ToArray() work? – Jared Bienz - MSFT Apr 23 '09 at 14:50
  • @Jared: Because ToArray won't compile -- the type must match the underlying type of the list. – Randolpho Apr 23 '09 at 14:53
  • 3
    @JoshJordan: There's nothing wrong with the question. He's ignorant of some of the new extension methods in 3.5, that's all. He's tried two and failed. – Randolpho Apr 23 '09 at 14:55
  • 1
    I don't understand the aversion to using a loop. Chances are that any one-line solution is just executing a loop internally anyway. In fact, if the extension methods didn't exist, you could write your own... using a loop. – Michael Meadows Apr 23 '09 at 14:58
  • @Michael: You're right, an internal loop is absolutely necessary; there's no getting away from it. But it can be done in one line easily; see my answer for details. – Randolpho Apr 23 '09 at 15:00
  • I dunno who downvoted you for this, but there was no need; it's a valid question. – Randolpho Apr 23 '09 at 17:37

8 Answers8

74
mylist.Cast<object>().ToArray()

That will only iterate once, by the way, in case you were wondering about the performance. O(n). :)

Why? Well, because Cast<object> will use deferred execution and won't actually do anything until the list is iterated by ToArray().

Randolpho
  • 55,384
  • 17
  • 145
  • 179
10
List<T>.Select(x => x as object).ToArray();

Should return an object[].

Çağdaş Tekin
  • 16,592
  • 4
  • 49
  • 58
  • 1
    This should have been the accepted answer! @Randolpho – Mike Jul 19 '17 at 17:23
  • 2
    @Mike I disagree. Yes, they're functionally equivalent, but `Cast` is a better choice because it doesn't require or create a lambda. Lambdas may be cheap, but they're not free. – Randolpho Jul 24 '17 at 22:11
3

If you don't have Linq (.Net 3.0) then you can use the ConvertAll() and ToArray() methods in List:

List<T> list = new List<T>();

object[] objects = list.ConvertAll<object>(item => (object)item).ToArray();
jrummell
  • 42,637
  • 17
  • 112
  • 171
2
theList.Cast<object>().ToArray()

or

new List<object>(theList).ToArray()
Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • 2
    Your first is preferrable. Your second option will iterate over the list twice. Cast will not actually iterate over the list. – Randolpho Apr 23 '09 at 14:57
  • @Randolpho, correct me if I'm wrong, but ToArray has to traverse the list in order to create an array. The casting is deferred until this occurs, but since it happens on the same line, it's effectviely iterating the entire list. Option 2, however does look like it would iterate twice. – Michael Meadows Apr 23 '09 at 15:02
  • @Michael: That's what he said. The second would iterate twice. – Samuel Apr 23 '09 at 15:04
  • @Stefan: The second will iterate twice because the List constructor will iterate over the original list to build its internal array. Then the ToArray() call will iterate over it to transform it to an array. You may be thinking that ToArray will return the List's internal array, but this is not the case. See http://msdn.microsoft.com/en-us/library/x303t819.aspx for details – Randolpho Apr 23 '09 at 15:08
  • @Samuel, I was agreeing with the assessment that option two iterates twice, but questioning the assertion that Cast will not iterate. While that statement in isolation is true, it might lead people to believe that there's no iteration. I don't think that's what @Randolpho was trying to say, but it just appears to say it. I was just looking for clarification. – Michael Meadows Apr 23 '09 at 15:43
  • @both: My apologies for the miscommunication. To be clear: The first option will iterate once, because the call to ToArray() will iterate over the enumeration, but the call to Cast() will not iterate, as it uses deferred execution. See my answer for a link explaining how that works. The second option will iterate twice because the List constructor will iterate during construction, and the ToArray() call will iterate a second time to build the array. – Randolpho Apr 23 '09 at 18:19
  • Hm, I never tired to propose the most optimized solution, but the most readable or intuitive. Things that people understand and can remember are also important. – Stefan Steinegger Apr 23 '09 at 20:34
  • @Stefan Steinegger, the easiest to read and maintain should always be the first solution, but it's also important to understand the performance implications of your algorithms. That way, if it does become a performance bottleneck, you know exactly why, and have alternatives ready. Also, if you have two relatively equatable solutions available (as above), performance may be the deciding criterion. – Michael Meadows Apr 24 '09 at 13:47
  • @Michael: I agree. The only reason why I also proposed the other was the fact that some people don't know / use Link. It's the "old school" style which even a C# beginner should understand. – Stefan Steinegger Apr 24 '09 at 13:56
2

And for a pre-LINQ solution (that only works for reference types).

(object[])List<T>.ToArray();
Community
  • 1
  • 1
Samuel
  • 37,778
  • 11
  • 85
  • 87
  • You don't need the cast, reference types are all objects anyway. – stevehipwell Apr 23 '09 at 15:12
  • @Stevo3000 he certainly does need the cast, since that's a requirement of the original question. Casting to an array of objects. – Randolpho Apr 23 '09 at 18:24
  • @Randolpho - Not true, all reference types are objects. Just because the question asks for a cast does not mean it is required. Any reference type can be stored as an object. – stevehipwell Apr 24 '09 at 07:52
1

If you don't mind writing a very short, reusable function, the ConvertAll Extension Method might help:

http://msdn.microsoft.com/en-us/library/73fe8cwf.aspx

EDIT:

This would work too

List<int> intList = new List<int>() { 1, 3, 4 };
object[] objectList = intList.ConvertAll(item => (object)item).ToArray();
Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
0

In C# on .NET 2.0 (VS 2008) the following compiles and doesn't use LINQ (as far as I can see) for reference types.

 object[] oArray;
 List<MyObject> oList = new List<MyObject>();
 oArray = oList.ToArray();

This does not require a cast as all reference types have object as their base.

stevehipwell
  • 56,138
  • 6
  • 44
  • 61
-1

I'd suggest creating a ListCastAdapter,

Lets say you want to Convert List to List

Create implementation of an implementation of IList that return items from a List

most likely i call it class ListCastAdapter

Have a great day

implementation (NOT TESTED):

Notice: It is recomended to make the list ReadOnly, for the fact, now the user can insert objects that are way up the hierarchy in the original list.

Note: CopyTo() is not implemented, you can create the same idea for the array.

using System.Collections;
using System.Collections.Generic;

namespace UDF.MyDataLayer
{
    internal class ListCastAdapter<S,T> : IList<T> where T : class where S : class
    {
        private List<S> adaptee;

        public ListCastAdapter(List<S> adaptee )
        {
            this.adaptee = adaptee;
        }

        #region Implementation of IEnumerable

        public class EnumeratorCastAdapter : IEnumerator<T>
        {
            private IEnumerator<S> adaptee;

            public EnumeratorCastAdapter(IEnumerator<S> adaptee)
            {
                this.adaptee = adaptee;
            }

            #region Implementation of IDisposable

            /// <summary>
            /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
            /// </summary>
            /// <filterpriority>2</filterpriority>
            public void Dispose()
            {
                adaptee.Dispose();
            }

            #endregion

            #region Implementation of IEnumerator
            /// <summary>
            /// Advances the enumerator to the next element of the collection.
            /// </summary>
            /// <returns>
            /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
            /// </returns>
            /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
            public bool MoveNext()
            {
                return adaptee.MoveNext();
            }

            /// <summary>
            /// Sets the enumerator to its initial position, which is before the first element in the collection.
            /// </summary>
            /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
            public void Reset()
            {
                adaptee.Reset();
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            public T Current
            {
                get
                {
                    // needs to check if it is an Object or Value Type
                    return adaptee.Current as T;
                }
            }

            /// <summary>
            /// Gets the current element in the collection.
            /// </summary>
            /// <returns>
            /// The current element in the collection.
            /// </returns>
            /// <exception cref="T:System.InvalidOperationException">The enumerator is positioned before the first element of the collection or after the last element.</exception><filterpriority>2</filterpriority>
            object IEnumerator.Current
            {
                get { return Current; }
            }
            #endregion
        }
        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        public IEnumerator<T> GetEnumerator()
        {
            return new EnumeratorCastAdapter(adaptee.GetEnumerator());
        }

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return adaptee.GetEnumerator();
        }
        #endregion

        #region Implementation of ICollection<T>
        /// <summary>
        /// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
        /// </summary>
        /// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
        public void Add(T item)
        {
            adaptee.Add(item as S);
        }

        /// <summary>
        /// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
        /// </summary>
        /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception>
        public void Clear()
        {
            adaptee.Clear();
        }

        /// <summary>
        /// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
        /// </summary>
        /// <returns>
        /// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
        /// </returns>
        /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
        public bool Contains(T item)
        {
            return adaptee.Contains(item as S);
        }

        /// <summary>
        /// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
        /// </summary>
        /// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or-The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.-or-Type <paramref name="T"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception>
        public void CopyTo(T[] array, int arrayIndex)
        {
            throw new System.NotImplementedException("Not Needed by Me, implement ArrayCastAdapter if needed");
        }

        /// <summary>
        /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
        /// </summary>
        /// <returns>
        /// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
        /// </returns>
        /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
        public bool Remove(T item)
        {
            adaptee.Remove(item as S);
        }

        /// <summary>
        /// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
        /// </summary>
        /// <returns>
        /// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
        /// </returns>
        public int Count
        {
            get { return adaptee.Count; }
        }

        /// <summary>
        /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
        /// </summary>
        /// <returns>
        /// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
        /// </returns>
        public bool IsReadOnly
        {
            get 
            {
                return true;  // change, to live on the edge
            }
        }
        #endregion

        #region Implementation of IList<T>
        /// <summary>
        /// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"/>.
        /// </summary>
        /// <returns>
        /// The index of <paramref name="item"/> if found in the list; otherwise, -1.
        /// </returns>
        /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
        public int IndexOf(T item)
        {
            return adaptee.IndexOf(item as S);
        }

        /// <summary>
        /// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"/> at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param><param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1"/>.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.</exception>
        public void Insert(int index, T item)
        {
            adaptee.Insert(index, item as S);
        }

        /// <summary>
        /// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the item to remove.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.</exception>
        public void RemoveAt(int index)
        {
            adaptee.RemoveAt(index);
        }

        /// <summary>
        /// Gets or sets the element at the specified index.
        /// </summary>
        /// <returns>
        /// The element at the specified index.
        /// </returns>
        /// <param name="index">The zero-based index of the element to get or set.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.</exception><exception cref="T:System.NotSupportedException">The property is set and the <see cref="T:System.Collections.Generic.IList`1"/> is read-only.</exception>
        public T this[int index]
        {
            get { return adaptee[index] as T; }
            set { adaptee[index] = value as S; }
        }
        #endregion
    }
}
Tomer W
  • 3,395
  • 2
  • 29
  • 44
  • 2
    Nice one liner you got here... Could you explain how this is better than the accepted answer (which is more than two years old)? – jv42 Jan 10 '12 at 15:03
  • The Linq Statment will iterate all the variables and return a casted array... but it is still O(n)... if you need only few members, this method will perform only on those you need, when you need them. lets assume you have 100000 records, and you need the list casted, while you know the list will be requested for few records only... why use O(n) if you can use O(a):a< – Tomer W Feb 01 '12 at 11:14
  • Then could you explain how your post answers the question, which is to get a List<> as an Array, not get a few items from a List. Maybe an usage example would make it clear? – jv42 Feb 01 '12 at 14:46
  • Well as awkward as it sound, The post right below is the best for most cases.. for the case of value types, this can be used, BTW @jv42 it's not the goal to have an object[] specifically, but a goal of having an array of type object, which List is providing. what i was suggesting is a "Lazy Initialization" of such array. – Tomer W Feb 02 '12 at 11:59