Avoid dynamic in AddRange detection

This commit is contained in:
Marek Lemańczyk committed 2025-07-14 19:27:25 +02:00
1 parent 976c5eb78b
commit 1d4d5e9217
2 files changed
+138 -28

No files matched your search

@@ -1,13 +1,74 @@
using System.Collections; using System.Collections;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Linq.Expressions;
using System.Reflection;
namespace Recyclable.Collections namespace Recyclable.Collections
{ {
public static class zRecyclableListAddRange public static class zRecyclableListAddRange
{ {
private static void AddRangeEnumerated<T>(this RecyclableList<T> list, IEnumerable<T> items, int growByCount) private static class AddRangeHelper<T>
{ {
internal static readonly Type? DictionaryType;
internal static readonly Type? SortedListType;
internal static readonly Action<RecyclableList<T>, IEnumerable<T>>? DictionaryAdder;
internal static readonly Action<RecyclableList<T>, IEnumerable<T>>? SortedListAdder;
static AddRangeHelper()
{
var itemType = typeof(T);
if (itemType.IsGenericType)
{
var genericDefinition = itemType.GetGenericTypeDefinition();
if (genericDefinition == typeof(KeyValuePair<,>))
{
var args = itemType.GetGenericArguments();
DictionaryType = typeof(RecyclableDictionary<,>).MakeGenericType(args);
var listType = typeof(RecyclableList<>).MakeGenericType(itemType);
var method = typeof(zRecyclableListAddRange).GetMethod(
nameof(AddRange),
BindingFlags.NonPublic | BindingFlags.Static,
null,
new[] { listType, DictionaryType },
null)!.MakeGenericMethod(args);
var listParam = Expression.Parameter(typeof(RecyclableList<T>), "list");
var itemsParam = Expression.Parameter(typeof(IEnumerable<T>), "items");
var call = Expression.Call(method,
Expression.Convert(listParam, listType),
Expression.Convert(itemsParam, DictionaryType));
DictionaryAdder = Expression.Lambda<Action<RecyclableList<T>, IEnumerable<T>>>(call, listParam, itemsParam).Compile();
}
else if (genericDefinition == typeof(ValueTuple<,>))
{
var args = itemType.GetGenericArguments();
SortedListType = typeof(RecyclableSortedList<,>).MakeGenericType(args);
var listType = typeof(RecyclableList<>).MakeGenericType(itemType);
var method = typeof(zRecyclableListAddRange).GetMethod(
nameof(AddRange),
BindingFlags.NonPublic | BindingFlags.Static,
null,
new[] { listType, SortedListType },
null)!.MakeGenericMethod(args);
var listParam = Expression.Parameter(typeof(RecyclableList<T>), "list");
var itemsParam = Expression.Parameter(typeof(IEnumerable<T>), "items");
var call = Expression.Call(method,
Expression.Convert(listParam, listType),
Expression.Convert(itemsParam, SortedListType));
SortedListAdder = Expression.Lambda<Action<RecyclableList<T>, IEnumerable<T>>>(call, listParam, itemsParam).Compile();
}
}
}
}
private static void AddRangeEnumerated<T>(this RecyclableList<T> list, IEnumerable<T> items, int growByCount)
{
var enumerator = items.GetEnumerator(); var enumerator = items.GetEnumerator();
if (!enumerator.MoveNext()) if (!enumerator.MoveNext())
{ {
@@ -577,19 +638,13 @@ namespace Recyclable.Collections
{ {
AddRange(list, sourceQueue); AddRange(list, sourceQueue);
} }
else if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(KeyValuePair<,>) else if (AddRangeHelper<T>.DictionaryAdder != null && AddRangeHelper<T>.DictionaryType!.IsInstanceOfType(items))
&& items.GetType().IsGenericType && items.GetType().GetGenericTypeDefinition() == typeof(RecyclableDictionary<,>))
{ {
dynamic dynList = list; AddRangeHelper<T>.DictionaryAdder!(list, items);
dynamic dynDict = items;
AddRange(dynList, dynDict);
} }
else if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(ValueTuple<,>) else if (AddRangeHelper<T>.SortedListAdder != null && AddRangeHelper<T>.SortedListType!.IsInstanceOfType(items))
&& items.GetType().IsGenericType && items.GetType().GetGenericTypeDefinition() == typeof(RecyclableSortedList<,>))
{ {
dynamic dynList = list; AddRangeHelper<T>.SortedListAdder!(list, items);
dynamic dynSortedList = items;
AddRange(dynList, dynSortedList);
} }
else if (items is IReadOnlyList<T> sourceIReadOnlyList) else if (items is IReadOnlyList<T> sourceIReadOnlyList)
{ {
@@ -1,14 +1,75 @@
using System.Collections; using System.Collections;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Linq.Expressions;
using System.Reflection;
using Recyclable.Collections.Pools; using Recyclable.Collections.Pools;
namespace Recyclable.Collections namespace Recyclable.Collections
{ {
public static class zRecyclableLongListAddRange public static class zRecyclableLongListAddRange
{ {
private static void AddRangeEnumerated<T>(this RecyclableLongList<T> targetList, IEnumerable<T> items) private static class AddRangeHelper<T>
{ {
internal static readonly Type? DictionaryType;
internal static readonly Type? SortedListType;
internal static readonly Action<RecyclableLongList<T>, IEnumerable<T>>? DictionaryAdder;
internal static readonly Action<RecyclableLongList<T>, IEnumerable<T>>? SortedListAdder;
static AddRangeHelper()
{
var itemType = typeof(T);
if (itemType.IsGenericType)
{
var genericDefinition = itemType.GetGenericTypeDefinition();
if (genericDefinition == typeof(KeyValuePair<,>))
{
var args = itemType.GetGenericArguments();
DictionaryType = typeof(RecyclableDictionary<,>).MakeGenericType(args);
var listType = typeof(RecyclableLongList<>).MakeGenericType(itemType);
var method = typeof(zRecyclableLongListAddRange).GetMethod(
nameof(AddRange),
BindingFlags.NonPublic | BindingFlags.Static,
null,
new[] { listType, DictionaryType },
null)!.MakeGenericMethod(args);
var listParam = Expression.Parameter(typeof(RecyclableLongList<T>), "list");
var itemsParam = Expression.Parameter(typeof(IEnumerable<T>), "items");
var call = Expression.Call(method,
Expression.Convert(listParam, listType),
Expression.Convert(itemsParam, DictionaryType));
DictionaryAdder = Expression.Lambda<Action<RecyclableLongList<T>, IEnumerable<T>>>(call, listParam, itemsParam).Compile();
}
else if (genericDefinition == typeof(ValueTuple<,>))
{
var args = itemType.GetGenericArguments();
SortedListType = typeof(RecyclableSortedList<,>).MakeGenericType(args);
var listType = typeof(RecyclableLongList<>).MakeGenericType(itemType);
var method = typeof(zRecyclableLongListAddRange).GetMethod(
nameof(AddRange),
BindingFlags.NonPublic | BindingFlags.Static,
null,
new[] { listType, SortedListType },
null)!.MakeGenericMethod(args);
var listParam = Expression.Parameter(typeof(RecyclableLongList<T>), "list");
var itemsParam = Expression.Parameter(typeof(IEnumerable<T>), "items");
var call = Expression.Call(method,
Expression.Convert(listParam, listType),
Expression.Convert(itemsParam, SortedListType));
SortedListAdder = Expression.Lambda<Action<RecyclableLongList<T>, IEnumerable<T>>>(call, listParam, itemsParam).Compile();
}
}
}
}
private static void AddRangeEnumerated<T>(this RecyclableLongList<T> targetList, IEnumerable<T> items)
{
using IEnumerator<T> enumerator = items.GetEnumerator(); using IEnumerator<T> enumerator = items.GetEnumerator();
if (!enumerator.MoveNext()) if (!enumerator.MoveNext())
{ {
@@ -438,18 +499,12 @@ namespace Recyclable.Collections
targetList.AddRange(sourceQueue); targetList.AddRange(sourceQueue);
return; return;
case var _ when typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(KeyValuePair<,>) case var _ when AddRangeHelper<T>.DictionaryAdder != null && AddRangeHelper<T>.DictionaryType!.IsInstanceOfType(items):
&& items.GetType().IsGenericType && items.GetType().GetGenericTypeDefinition() == typeof(RecyclableDictionary<,>): AddRangeHelper<T>.DictionaryAdder!(targetList, items);
dynamic dynTargetList = targetList;
dynamic dynDict = items;
AddRange(dynTargetList, dynDict);
return; return;
case var _ when typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(ValueTuple<,>) case var _ when AddRangeHelper<T>.SortedListAdder != null && AddRangeHelper<T>.SortedListType!.IsInstanceOfType(items):
&& items.GetType().IsGenericType && items.GetType().GetGenericTypeDefinition() == typeof(RecyclableSortedList<,>): AddRangeHelper<T>.SortedListAdder!(targetList, items);
dynamic dynTargetList2 = targetList;
dynamic dynSortedList = items;
AddRange(dynTargetList2, dynSortedList);
return; return;
default: default: