2016-06-16 13 views
1

のタイプTが実行時(コンパイル時ではない)でしか認識されない場合、ImmutableList<T>を生成したいと考えています。コンパイル時に不明な型の不変型リストを作成する

Iのようなようなこと作成したい方法

var immutableList = CreateImmutableList(originalList, type); 

originalListがIEnumerableとタイプが生成ImmutableList<T>ののTです。

どのように!

(私はNET .Coreで働いている)

編集:私は実用的なソリューションを発見したコメントに感謝します。 AddRangeメソッドを使用します。

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 }); 
     } 
    } 
} 
+0

このwon't作品。コンパイル時に 'Collection 'を簡単に作ることができるタイプを知っているか、コンパイラが実行時に何を提供するかを推測することができないタイプを知っていません。 – HimBromBeere

+1

'CreateImmutableList'は' ImmutableList 'を返すことができないので、'オブジェクト 'を返す必要があります(結局のところ、' T'を知りません)。それはあなたが欲しいものですか?その場合、 'var'がどのような型であるべきかを明示してください。 –

+0

'originalList'も実行時に' IEnumerable 'ですか? –

答えて

3
に値型の所有である場合には、パフォーマンスへの影響を有することができます

あなたは、この使用して反射を行うことができます。

  1. ImmutableList<T>
  2. のための右のTypeオブジェクトを作成し、データ
  3. でそれを埋めます
  4. 返信する

ここに示したLINQPadプログラムです。私は "不変のリスト" であなたはNugetを通じて利用できるSystem.Collections.Immutable.ImmutableList<T>を意味すると仮定しています:

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; 
} 

出力:

System.Collections.Immutable.ImmutableList`1[System.Int32] 

1 
2 
3 
4 
5 
+0

クール!しかし、コレクションがArrayList型またはCollection型である場合は動作しません SuperJMN

+0

ArrayListは汎用ではないため、Collection >では動作しますが、ArrayListでは動作しません。とにかくArrayListを使っているのはなぜですか? –

+1

'ArrayList'を扱う' IEnumerable'( ''なし)をサポートするように編集されました。私は 'Collection 'でテストしたので、テストした内容を教えてください。 –

0

あなたはボクシング/アンボクシングのために準備ができているならば、あなたはここでは、この

  var objectCollection = new Collection<object>(); 
      objectCollection.Add(3); 
      objectCollection.Add(4); 
      var immutableList = objectCollection.ToImmutableList(); 

ような何かを行うことができ、要素タイプはintであり、我々は、オブジェクトのコレクションに値を追加します。私たちが入力した値を取り戻すしたい場合は、我々は行うことができます。

foreach (var obj in immutableList) 
       { 
        int myVal = (int) Convert.ChangeType(obj, typeof(int)); 
        Console.WriteLine(myVal); 
       } 

注:あなたのリストが大きく、要素タイプはボクシング/アンボクシング

関連する問題