Json.NET
Code Coverage Statistics for Source File

Newtonsoft.Json\Utilities\CollectionUtils.cs

Symbol Coverage: 42.86% (123 of 287)

Branch Coverage: 37.06% (63 of 170)

Cyclomatic Complexity Avg: 3.05 Max:17

Code Lines: 267


L V Source
1
#region License
2
// Copyright (c) 2007 James Newton-King
3
//
4
// Permission is hereby granted, free of charge, to any person
5
// obtaining a copy of this software and associated documentation
6
// files (the "Software"), to deal in the Software without
7
// restriction, including without limitation the rights to use,
8
// copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the
10
// Software is furnished to do so, subject to the following
11
// conditions:
12
//
13
// The above copyright notice and this permission notice shall be
14
// included in all copies or substantial portions of the Software.
15
//
16
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
// OTHER DEALINGS IN THE SOFTWARE.
24
#endregion
25

  
26
using System;
27
using System.Collections.Generic;
28
using System.Collections.ObjectModel;
29
using System.Reflection;
30
using System.Text;
31
using System.Collections;
32
using System.Linq;
33
using System.Globalization;
34

  
35
namespace Newtonsoft.Json.Utilities
36
{
37
  internal static class CollectionUtils
38
  {
39
    public static IEnumerable<T> CastValid<T>(this IEnumerable enumerable)
40
    {
41
 0
      ValidationUtils.ArgumentNotNull(enumerable, "enumerable");
42

  
43
 0
      return enumerable.Cast<object>().Where(o => o is T).Cast<T>();
44
 0
    }
45

  
46
    public static List<T> CreateList<T>(params T[] values)
47
    {
48
 0
      return new List<T>(values);
49
 0
    }
50

  
51
    /// <summary>
52
    /// Determines whether the collection is null or empty.
53
    /// </summary>
54
    /// <param name="collection">The collection.</param>
55
    /// <returns>
56
    /// 	<c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
57
    /// </returns>
58
    public static bool IsNullOrEmpty(ICollection collection)
59
    {
60
 0
      if (collection != null)
61
      {
62
 0
        return (collection.Count == 0);
63
      }
64
 0
      return true;
65
 0
    }
66

  
67
    /// <summary>
68
    /// Determines whether the collection is null or empty.
69
    /// </summary>
70
    /// <param name="collection">The collection.</param>
71
    /// <returns>
72
    /// 	<c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
73
    /// </returns>
74
    public static bool IsNullOrEmpty<T>(ICollection<T> collection)
75
    {
76
 414
      if (collection != null)
77
      {
78
 254
        return (collection.Count == 0);
79
      }
80
 160
      return true;
81
 414
    }
82

  
83
    /// <summary>
84
    /// Determines whether the collection is null, empty or its contents are uninitialized values.
85
    /// </summary>
86
    /// <param name="list">The list.</param>
87
    /// <returns>
88
    /// 	<c>true</c> if the collection is null or empty or its contents are uninitialized values; otherwise, <c>false</c>.
89
    /// </returns>
90
    public static bool IsNullOrEmptyOrDefault<T>(IList<T> list)
91
    {
92
 0
      if (IsNullOrEmpty<T>(list))
93
 0
        return true;
94

  
95
 0
      return ReflectionUtils.ItemsUnitializedValue<T>(list);
96
 0
    }
97

  
98
    /// <summary>
99
    /// Makes a slice of the specified list in between the start and end indexes.
100
    /// </summary>
101
    /// <param name="list">The list.</param>
102
    /// <param name="start">The start index.</param>
103
    /// <param name="end">The end index.</param>
104
    /// <returns>A slice of the list.</returns>
105
    public static IList<T> Slice<T>(IList<T> list, int? start, int? end)
106
    {
107
 0
      return Slice<T>(list, start, end, null);
108
 0
    }
109

  
110
    /// <summary>
111
    /// Makes a slice of the specified list in between the start and end indexes,
112
    /// getting every so many items based upon the step.
113
    /// </summary>
114
    /// <param name="list">The list.</param>
115
    /// <param name="start">The start index.</param>
116
    /// <param name="end">The end index.</param>
117
    /// <param name="step">The step.</param>
118
    /// <returns>A slice of the list.</returns>
119
    public static IList<T> Slice<T>(IList<T> list, int? start, int? end, int? step)
120
    {
121
 0
      if (list == null)
122
 0
        throw new ArgumentNullException("list");
123

  
124
 0
      if (step == 0)
125
 0
        throw new ArgumentException("Step cannot be zero.", "step");
126

  
127
 0
      List<T> slicedList = new List<T>();
128

  
129
      // nothing to slice
130
 0
      if (list.Count == 0)
131
 0
        return slicedList;
132

  
133
      // set defaults for null arguments
134
 0
      int s = step ?? 1;
135
 0
      int startIndex = start ?? 0;
136
 0
      int endIndex = end ?? list.Count;
137

  
138
      // start from the end of the list if start is negitive
139
 0
      startIndex = (startIndex < 0) ? list.Count + startIndex : startIndex;
140

  
141
      // end from the start of the list if end is negitive
142
 0
      endIndex = (endIndex < 0) ? list.Count + endIndex : endIndex;
143

  
144
      // ensure indexes keep within collection bounds
145
 0
      startIndex = Math.Max(startIndex, 0);
146
 0
      endIndex = Math.Min(endIndex, list.Count - 1);
147

  
148
      // loop between start and end indexes, incrementing by the step
149
 0
      for (int i = startIndex; i < endIndex; i += s)
150
      {
151
 0
        slicedList.Add(list[i]);
152
      }
153

  
154
 0
      return slicedList;
155
 0
    }
156

  
157

  
158
    /// <summary>
159
    /// Group the collection using a function which returns the key.
160
    /// </summary>
161
    /// <param name="source">The source collection to group.</param>
162
    /// <param name="keySelector">The key selector.</param>
163
    /// <returns>A Dictionary with each key relating to a list of objects in a list grouped under it.</returns>
164
    public static Dictionary<K, List<V>> GroupBy<K, V>(ICollection<V> source, Func<V, K> keySelector)
165
    {
166
 0
      if (keySelector == null)
167
 0
        throw new ArgumentNullException("keySelector");
168

  
169
 0
      Dictionary<K, List<V>> groupedValues = new Dictionary<K, List<V>>();
170

  
171
 0
      foreach (V value in source)
172
      {
173
        // using delegate to get the value's key
174
 0
        K key = keySelector(value);
175
        List<V> groupedValueList;
176

  
177
        // add a list for grouped values if the key is not already in Dictionary
178
 0
        if (!groupedValues.TryGetValue(key, out groupedValueList))
179
        {
180
 0
          groupedValueList = new List<V>();
181
 0
          groupedValues.Add(key, groupedValueList);
182
        }
183

  
184
 0
        groupedValueList.Add(value);
185
      }
186

  
187
 0
      return groupedValues;
188
 0
    }
189

  
190
    /// <summary>
191
    /// Adds the elements of the specified collection to the specified generic IList.
192
    /// </summary>
193
    /// <param name="initial">The list to add to.</param>
194
    /// <param name="collection">The collection of elements to add.</param>
195
    public static void AddRange<T>(this IList<T> initial, IEnumerable<T> collection)
196
    {
197
 1187
      if (initial == null)
198
 0
        throw new ArgumentNullException("initial");
199

  
200
 1187
      if (collection == null)
201
 0
        return;
202

  
203
 1187
      foreach (T value in collection)
204
      {
205
 2481
        initial.Add(value);
206
      }
207
 1187
    }
208

  
209
    public static void AddRange(this IList initial, IEnumerable collection)
210
    {
211
 693
      ValidationUtils.ArgumentNotNull(initial, "initial");
212

  
213
 693
      ListWrapper<object> wrapper = new ListWrapper<object>(initial);
214
 693
      wrapper.AddRange(collection.Cast<object>());
215
 693
    }
216

  
217
    public static List<T> Distinct<T>(List<T> collection)
218
    {
219
 0
      List<T> distinctList = new List<T>();
220

  
221
 0
      foreach (T value in collection)
222
      {
223
 0
        if (!distinctList.Contains(value))
224
 0
          distinctList.Add(value);
225
      }
226

  
227
 0
      return distinctList;
228
 0
    }
229

  
230
    public static List<List<T>> Flatten<T>(params IList<T>[] lists)
231
    {
232
 0
      List<List<T>> flattened = new List<List<T>>();
233
 0
      Dictionary<int, T> currentList = new Dictionary<int, T>();
234

  
235
 0
      Recurse<T>(new List<IList<T>>(lists), 0, currentList, flattened);
236

  
237
 0
      return flattened;
238
 0
    }
239

  
240
    private static void Recurse<T>(IList<IList<T>> global, int current, Dictionary<int, T> currentSet, List<List<T>> flattenedResult)
241
    {
242
 0
      IList<T> currentArray = global[current];
243

  
244
 0
      for (int i = 0; i < currentArray.Count; i++)
245
      {
246
 0
        currentSet[current] = currentArray[i];
247

  
248
 0
        if (current == global.Count - 1)
249
        {
250
 0
          List<T> items = new List<T>();
251

  
252
 0
          for (int k = 0; k < currentSet.Count; k++)
253
          {
254
 0
            items.Add(currentSet[k]);
255
          }
256

  
257
 0
          flattenedResult.Add(items);
258
        }
259
        else
260
        {
261
 0
          Recurse(global, current + 1, currentSet, flattenedResult);
262
        }
263
      }
264
 0
    }
265

  
266
    public static List<T> CreateList<T>(ICollection collection)
267
    {
268
 0
      if (collection == null)
269
 0
        throw new ArgumentNullException("collection");
270

  
271
 0
      T[] array = new T[collection.Count];
272
 0
      collection.CopyTo(array, 0);
273

  
274
 0
      return new List<T>(array);
275
 0
    }
276

  
277
    public static bool ListEquals<T>(IList<T> a, IList<T> b)
278
    {
279
 0
      if (a == null || b == null)
280
 0
        return (a == null && b == null);
281

  
282
 0
      if (a.Count != b.Count)
283
 0
        return false;
284

  
285
 0
      EqualityComparer<T> comparer = EqualityComparer<T>.Default;
286

  
287
 0
      for (int i = 0; i < a.Count; i++)
288
      {
289
 0
        if (!comparer.Equals(a[i], b[i]))
290
 0
          return false;
291
      }
292

  
293
 0
      return true;
294
 0
    }
295

  
296
    #region GetSingleItem
297
    public static bool TryGetSingleItem<T>(IList<T> list, out T value)
298
    {
299
 0
      return TryGetSingleItem<T>(list, false, out value);
300
 0
    }
301

  
302
    public static bool TryGetSingleItem<T>(IList<T> list, bool returnDefaultIfEmpty, out T value)
303
    {
304
 0
      return MiscellaneousUtils.TryAction<T>(delegate { return GetSingleItem(list, returnDefaultIfEmpty); }, out value);
305
 0
    }
306

  
307
    public static T GetSingleItem<T>(IList<T> list)
308
    {
309
 0
      return GetSingleItem<T>(list, false);
310
 0
    }
311

  
312
    public static T GetSingleItem<T>(IList<T> list, bool returnDefaultIfEmpty)
313
    {
314
 4218
      if (list.Count == 1)
315
 185
        return list[0];
316
 4033
      else if (returnDefaultIfEmpty && list.Count == 0)
317
 4033
        return default(T);
318
      else
319
 0
        throw new Exception("Expected single {0} in list but got {1}.".FormatWith(CultureInfo.InvariantCulture, typeof(T), list.Count));
320
 4218
    }
321
    #endregion
322

  
323
    public static IList<T> Minus<T>(IList<T> list, IList<T> minus)
324
    {
325
 0
      ValidationUtils.ArgumentNotNull(list, "list");
326

  
327
 0
      List<T> result = new List<T>(list.Count);
328
 0
      foreach (T t in list)
329
      {
330
 0
        if (minus == null || !minus.Contains(t))
331
 0
          result.Add(t);
332
      }
333

  
334
 0
      return result;
335
 0
    }
336

  
337
    public static IList CreateGenericList(Type listType)
338
    {
339
 1
      ValidationUtils.ArgumentNotNull(listType, "listType");
340

  
341
 1
      return (IList)ReflectionUtils.CreateGeneric(typeof(List<>), listType);
342
 1
    }
343

  
344
    public static IDictionary CreateGenericDictionary(Type keyType, Type valueType)
345
    {
346
 0
      ValidationUtils.ArgumentNotNull(keyType, "keyType");
347
 0
      ValidationUtils.ArgumentNotNull(valueType, "valueType");
348

  
349
 0
      return (IDictionary)ReflectionUtils.CreateGeneric(typeof(Dictionary<,>), keyType, valueType);
350
 0
    }
351

  
352
    public static bool IsListType(Type type)
353
    {
354
 0
      ValidationUtils.ArgumentNotNull(type, "type");
355

  
356
 0
      if (type.IsArray)
357
 0
        return true;
358
 0
      if (typeof(IList).IsAssignableFrom(type))
359
 0
        return true;
360
 0
      if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(IList<>)))
361
 0
        return true;
362

  
363
 0
      return false;
364
 0
    }
365

  
366
    public static bool IsCollectionType(Type type)
367
    {
368
 0
      ValidationUtils.ArgumentNotNull(type, "type");
369

  
370
 0
      if (type.IsArray)
371
 0
        return true;
372
 0
      if (typeof(ICollection).IsAssignableFrom(type))
373
 0
        return true;
374
 0
      if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(ICollection<>)))
375
 0
        return true;
376

  
377
 0
      return false;
378
 0
    }
379

  
380
    public static bool IsDictionaryType(Type type)
381
    {
382
 248
      ValidationUtils.ArgumentNotNull(type, "type");
383

  
384
 248
      if (typeof(IDictionary).IsAssignableFrom(type))
385
 14
        return true;
386
 234
      if (ReflectionUtils.ImplementsGenericDefinition(type, typeof (IDictionary<,>)))
387
 2
        return true;
388

  
389
 232
      return false;
390
 248
    }
391

  
392
    public static IWrappedCollection CreateCollectionWrapper(object list)
393
    {
394
 2
      ValidationUtils.ArgumentNotNull(list, "list");
395

  
396
      Type collectionDefinition;
397
 2
      if (ReflectionUtils.ImplementsGenericDefinition(list.GetType(), typeof(ICollection<>), out collectionDefinition))
398
      {
399
 2
        Type collectionItemType = ReflectionUtils.GetCollectionItemType(collectionDefinition);
400

  
401
        // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
402
 2
        Func<Type, IList<object>, object> instanceCreator = (t, a) =>
403
 2
        {
404
 2
          ConstructorInfo c = t.GetConstructor(new[] { collectionDefinition });
405
 2
          return c.Invoke(new[] { list });
406
 2
        };
407

  
408
 2
        return (IWrappedCollection)ReflectionUtils.CreateGeneric(typeof(CollectionWrapper<>), new[] { collectionItemType }, instanceCreator, list);
409
      }
410
 0
      else if (list is IList)
411
      {
412
 0
        return new CollectionWrapper<object>((IList)list);
413
      }
414
      else
415
      {
416
 0
        throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType()));
417
      }
418
 2
    }
419
    public static IWrappedList CreateListWrapper(object list)
420
    {
421
 0
      ValidationUtils.ArgumentNotNull(list, "list");
422

  
423
      Type listDefinition;
424
 0
      if (ReflectionUtils.ImplementsGenericDefinition(list.GetType(), typeof(IList<>), out listDefinition))
425
      {
426
 0
        Type collectionItemType = ReflectionUtils.GetCollectionItemType(listDefinition);
427

  
428
        // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
429
 0
        Func<Type, IList<object>, object> instanceCreator = (t, a) =>
430
 0
        {
431
 0
          ConstructorInfo c = t.GetConstructor(new[] {listDefinition});
432
 0
          return c.Invoke(new[] { list });
433
 0
        };
434

  
435
 0
        return (IWrappedList)ReflectionUtils.CreateGeneric(typeof(ListWrapper<>), new[] { collectionItemType }, instanceCreator, list);
436
      }
437
 0
      else if (list is IList)
438
      {
439
 0
        return new ListWrapper<object>((IList)list);
440
      }
441
      else
442
      {
443
 0
        throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType()));
444
      }
445
 0
    }
446

  
447
    public static IWrappedDictionary CreateDictionaryWrapper(object dictionary)
448
    {
449
 1
      ValidationUtils.ArgumentNotNull(dictionary, "dictionary");
450

  
451
      Type dictionaryDefinition;
452
 1
      if (ReflectionUtils.ImplementsGenericDefinition(dictionary.GetType(), typeof(IDictionary<,>), out dictionaryDefinition))
453
      {
454
 1
        Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryDefinition);
455
 1
        Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryDefinition);
456

  
457
        // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
458
 1
        Func<Type, IList<object>, object> instanceCreator = (t, a) =>
459
 1
        {
460
 1
          ConstructorInfo c = t.GetConstructor(new[] { dictionaryDefinition });
461
 1
          return c.Invoke(new[] { dictionary });
462
 1
        };
463

  
464
 1
        return (IWrappedDictionary)ReflectionUtils.CreateGeneric(typeof(DictionaryWrapper<,>), new[] { dictionaryKeyType, dictionaryValueType }, instanceCreator, dictionary);
465
      }
466
 0
      else if (dictionary is IDictionary)
467
      {
468
 0
        return new DictionaryWrapper<object, object>((IDictionary)dictionary);
469
      }
470
      else
471
      {
472
 0
        throw new Exception("Can not create DictionaryWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, dictionary.GetType()));
473
      }
474
 1
    }
475

  
476
    public static object CreateAndPopulateList(Type listType, Action<IList, bool> populateList)
477
    {
478
 20079
      ValidationUtils.ArgumentNotNull(listType, "listType");
479
 20079
      ValidationUtils.ArgumentNotNull(populateList, "populateList");
480

  
481
      IList list;
482
      Type collectionType;
483
 20079
      bool isReadOnlyOrFixedSize = false;
484

  
485
 20079
      if (listType.IsArray)
486
      {
487
        // have to use an arraylist when creating array
488
        // there is no way to know the size until it is finised
489
 27
        list = new List<object>();
490
 27
        isReadOnlyOrFixedSize = true;
491
      }
492
 20052
      else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>), out collectionType))
493
      {
494
 1
        Type readOnlyCollectionContentsType = collectionType.GetGenericArguments()[0];
495
 1
        Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType);
496
 1
        bool suitableConstructor = false;
497

  
498
 1
        foreach (ConstructorInfo constructor in listType.GetConstructors())
499
        {
500
 1
          IList<ParameterInfo> parameters = constructor.GetParameters();
501

  
502
 1
          if (parameters.Count == 1)
503
          {
504
 1
            if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
505
            {
506
 1
              suitableConstructor = true;
507
 1
              break;
508
            }
509
          }
510
        }
511

  
512
 1
        if (!suitableConstructor)
513
 0
          throw new Exception("Read-only type {0} does not have a public constructor that takes a type that implements {1}.".FormatWith(CultureInfo.InvariantCulture, listType, genericEnumerable));
514

  
515
        // can't add or modify a readonly list
516
        // use List<T> and convert once populated
517
 1
        list = CreateGenericList(readOnlyCollectionContentsType);
518
 1
        isReadOnlyOrFixedSize = true;
519
      }
520
 20051
      else if (typeof(IList).IsAssignableFrom(listType))
521
      {
522
 20050
        if (ReflectionUtils.IsInstantiatableType(listType))
523
 20050
          list = (IList)Activator.CreateInstance(listType);
524
 0
        else if (listType == typeof(IList))
525
 0
          list = new List<object>();
526
        else
527
 0
          list = null;
528
      }
529
 1
      else if (ReflectionUtils.ImplementsGenericDefinition(listType, typeof(ICollection<>)))
530
      {
531
 1
        if (ReflectionUtils.IsInstantiatableType(listType))
532
 1
          list = CreateCollectionWrapper(Activator.CreateInstance(listType));
533
        else
534
 0
          list = null;
535
      }
536
      else
537
      {
538
 0
        list = null;
539
      }
540

  
541
 20079
      if (list == null)
542
 0
        throw new Exception("Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, listType));
543

  
544
 20079
      populateList(list, isReadOnlyOrFixedSize);
545

  
546
      // create readonly and fixed sized collections using the temporary list
547
 20075
      if (isReadOnlyOrFixedSize)
548
      {
549
 27
        if (listType.IsArray)
550
 26
          list = ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetCollectionItemType(listType));
551
 1
        else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>)))
552
 1
          list = (IList)ReflectionUtils.CreateInstance(listType, list);
553
      }
554
 20048
      else if (list is IWrappedCollection)
555
      {
556
 1
        return ((IWrappedCollection) list).UnderlyingCollection;
557
      }
558

  
559
 20074
      return list;
560
 20075
    }
561

  
562
    public static Array ToArray(Array initial, Type type)
563
    {
564
 26
      if (type == null)
565
 0
        throw new ArgumentNullException("type");
566

  
567
 26
      Array destinationArray = Array.CreateInstance(type, initial.Length);
568
 26
      Array.Copy(initial, 0, destinationArray, 0, initial.Length);
569
 26
      return destinationArray;
570
 26
    }
571

  
572
    public static bool AddDistinct<T>(this IList<T> list, T value)
573
    {
574
 9
      return list.AddDistinct(value, EqualityComparer<T>.Default);
575
 9
    }
576

  
577
    public static bool AddDistinct<T>(this IList<T> list, T value, IEqualityComparer<T> comparer)
578
    {
579
 24
      if (list.ContainsValue(value, comparer))
580
 2
        return false;
581

  
582
 22
      list.Add(value);
583
 22
      return true;
584
 24
    }
585

  
586
    // this is here because LINQ Bridge doesn't support Contains with IEqualityComparer<T>
587
    public static bool ContainsValue<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
588
    {
589
 37
      if (comparer == null)
590
 0
        comparer = EqualityComparer<TSource>.Default;
591

  
592
 37
      if (source == null)
593
 0
        throw new ArgumentNullException("source");
594

  
595
 32
      foreach (TSource local in source)
596
      {
597
 32
        if (comparer.Equals(local, value))
598
 10
          return true;
599
      }
600

  
601
 27
      return false;
602
 37
    }
603

  
604
    public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values)
605
    {
606
 0
      return list.AddRangeDistinct(values, EqualityComparer<T>.Default);
607
 0
    }
608

  
609
    public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values, IEqualityComparer<T> comparer)
610
    {
611
 9
      bool allAdded = true;
612
 9
      foreach (T value in values)
613
      {
614
 15
        if (!list.AddDistinct(value, comparer))
615
 2
          allAdded = false;
616
      }
617

  
618
 9
      return allAdded;
619
 9
    }
620

  
621
    public static int IndexOf<T>(this IEnumerable<T> collection, Func<T, bool> predicate)
622
    {
623
 30
      int index = 0;
624
 30
      foreach (T value in collection)
625
      {
626
 357
        if (predicate(value))
627
 16
          return index;
628

  
629
 341
        index++;
630
      }
631

  
632
 14
      return -1;
633
 30
    }
634
  }
635
}