1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.Collections;
\r
6 using System.Collections.Generic;
\r
7 using System.Collections.ObjectModel;
\r
8 using System.Diagnostics.CodeAnalysis;
\r
9 using System.Globalization;
\r
12 namespace Microsoft.Internal.Collections
\r
14 internal static partial class CollectionServices
\r
16 private static readonly Type StringType = typeof(string);
\r
17 private static readonly Type IEnumerableType = typeof(IEnumerable);
\r
18 private static readonly Type IEnumerableOfTType = typeof(IEnumerable<>);
\r
19 private static readonly Type ICollectionOfTType = typeof(ICollection<>);
\r
21 public static bool IsEnumerableOfT(Type type)
\r
23 if (type.IsGenericType)
\r
25 Type genericType = type.GetGenericTypeDefinition();
\r
27 if (genericType == IEnumerableOfTType)
\r
35 public static Type GetEnumerableElementType(Type type)
\r
37 if (type == StringType || !IEnumerableType.IsAssignableFrom(type))
\r
43 if (ReflectionServices.TryGetGenericInterfaceType(type, IEnumerableOfTType, out closedType))
\r
45 return closedType.GetGenericArguments()[0];
\r
51 public static Type GetCollectionElementType(Type type)
\r
54 if (ReflectionServices.TryGetGenericInterfaceType(type, ICollectionOfTType, out closedType))
\r
56 return closedType.GetGenericArguments()[0];
\r
62 public static ReadOnlyCollection<T> ToReadOnlyCollection<T>(this IEnumerable<T> source)
\r
64 Assumes.NotNull(source);
\r
66 return new ReadOnlyCollection<T>(source.AsArray());
\r
69 public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T> source) where T : class
\r
71 Assumes.NotNull(source);
\r
72 return source.Where(NotNull); // Use non-generic NotNull for performance reasons
\r
75 private static bool NotNull(object element)
\r
77 return element != null;
\r
80 public static IEnumerable<T> ConcatAllowingNull<T>(this IEnumerable<T> source, IEnumerable<T> second)
\r
82 if (second == null || !second.FastAny())
\r
87 if (source == null || !source.FastAny())
\r
92 return source.Concat(second);
\r
95 public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
\r
97 foreach(T t in source)
\r
103 public static EnumerableCardinality GetCardinality<T>(this IEnumerable<T> source)
\r
105 Assumes.NotNull(source);
\r
107 // Cast to ICollection instead of ICollection<T> for performance reasons.
\r
108 ICollection collection = source as ICollection;
\r
109 if (collection != null)
\r
111 switch (collection.Count)
\r
114 return EnumerableCardinality.Zero;
\r
117 return EnumerableCardinality.One;
\r
120 return EnumerableCardinality.TwoOrMore;
\r
124 using (var enumerator = source.GetEnumerator())
\r
126 if (!enumerator.MoveNext())
\r
128 return EnumerableCardinality.Zero;
\r
131 if (!enumerator.MoveNext())
\r
133 return EnumerableCardinality.One;
\r
136 return EnumerableCardinality.TwoOrMore;
\r
140 public static bool FastAny<T>(this IEnumerable<T> source)
\r
142 // Enumerable.Any<T> underneath doesn't cast to ICollection,
\r
143 // like it does with many of the other LINQ methods.
\r
144 // Below is significantly (4x) when mainly working with ICollection
\r
145 // sources and a little slower if working with mainly IEnumerable<T>
\r
148 // Cast to ICollection instead of ICollection<T> for performance reasons.
\r
149 ICollection collection = source as ICollection;
\r
150 if (collection != null)
\r
152 return collection.Count > 0;
\r
155 return source.Any();
\r
158 public static Stack<T> Copy<T>(this Stack<T> stack)
\r
160 Assumes.NotNull(stack);
\r
162 // Stack<T>.GetEnumerator walks from top to bottom
\r
163 // of the stack, whereas Stack<T>(IEnumerable<T>)
\r
164 // pushes to bottom from top, so we need to reverse
\r
165 // the stack to get them in the right order.
\r
166 return new Stack<T>(stack.Reverse());
\r
169 public static T[] AsArray<T>(this IEnumerable<T> enumerable)
\r
171 T[] array = enumerable as T[];
\r
178 return enumerable.ToArray();
\r