Given a Collection<T>
whose type T
is only known in runtime (not at compile time), I would like to generate an ImmutableList<T>
.
The method I would like to create may like like:
var immutableList = CreateImmutableList(originalList, type);
where originalList is IEnumerable
and type is the T
of of the generated ImmutableList<T>
.
How?!
(I'm working with NET .Core)
EDIT: Thanks to the comments I have found a working solution. It uses AddRange method.
namespace Sample.Tests
{
using System;
using System.Collections;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using Xunit;
public class ImmutabilityTests
{
[Fact]
public void CollectionCanBeConvertedToImmutable()
{
var original = new Collection<object>() { 1, 2, 3, 4, };
var result = original.AsImmutable(typeof(int));
Assert.NotEmpty(result);
Assert.IsAssignableFrom<ImmutableList<int>>(result);
}
}
public static class ReflectionExtensions
{
public static IEnumerable AsImmutable(this IEnumerable collection, Type elementType)
{
var immutableType = typeof(ImmutableList<>).MakeGenericType(elementType);
var addRangeMethod = immutableType.GetMethod("AddRange");
var typedCollection = ToTyped(collection, elementType);
var emptyImmutableList = immutableType.GetField("Empty").GetValue(null);
emptyImmutableList = addRangeMethod.Invoke(emptyImmutableList, new[] { typedCollection });
return (IEnumerable)emptyImmutableList;
}
private static object ToTyped(IEnumerable original, Type type)
{
var method = typeof(Enumerable).GetMethod("Cast", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(type);
return method.Invoke(original, new object[] { original });
}
}
}
You can do this using reflection:
Type
object for ImmutableList<T>
Here is a LINQPad program that demonstrates. I'm assuming that by "immutable list" you mean System.Collections.Immutable.ImmutableList<T>
available through Nuget:
void Main()
{
object il = CreateImmutableList(new[] { 1, 2, 3, 4, 5 }, typeof(int));
il.GetType().Dump();
il.Dump();
}
public static object CreateImmutableList(IEnumerable collection, Type elementType)
{
// TODO: guard clauses for parameters == null
var resultType = typeof(ImmutableList<>).MakeGenericType(elementType);
var result = resultType.GetField("Empty").GetValue(null);
var add = resultType.GetMethod("Add");
foreach (var element in collection)
result = add.Invoke(result, new object[] { element });
return result;
}
Output:
System.Collections.Immutable.ImmutableList`1[System.Int32]
1
2
3
4
5