5

System.Type値をコンストラクターに提供することにより、List<Foo>または実行時にインスタンス化するにはどうすればよいですか?List<Bar>この質問には何度も答える必要がありますが、見つかりません。

最終的に、私は次のような拡張メソッドを作成したいと思います。

public static IEnumerable<T> CreateEnumerable<T>(this System.Collections.IEnumerable list, Type type){
    var stuff = something;

    // magic happens to stuff where stuff becomes an IEnumerable<T> and T is of type 'type'

    return stuff as IEnumerable<T>;
}
4

4 に答える 4

11

List<>リフレクションとMakeGenericTypeメソッドを使用して、実行時にのパラメータを指定できます。

var typeParam = typeof(Foo);
var listType = typeof(List<>).MakeGenericType(typeParam);

そして、Activatorクラスを使用してインスタンス化します

var list = Activator.CreateInstance(listType);

IEnumerableただし、をに変換しようとしているだけの場合IEnumerable<T>、Linqにはすでにこれを行うためのメソッド(CastおよびOfType)があります。

IEnumerable untypedList = ...

var foos = untypedList.Cast<Foo>(); // May throw InvalidCastException
var bars = untypedList.OfType<Bar>();
于 2013-03-02T15:59:14.990 に答える
0

Type typeパラメータを一般的な引数と論理的に一致させることはできません< T >

拡張メソッドは非ジェネリックを返す必要がありIEnumerableます。

この構文IEnumerableが実際に(実行時に)ジェネリックを保持するようにすることは可能ですIEnumerable < That particular type > が、拡張メソッドを実行するユーザープログラマーは、仮定、チェック、および強制キャストを行う必要があります。

InvalidCastExceptionこのルートをたどり、ユーザープログラマーが物事に気付いていない場合は、最終的になる可能性があることに注意してください:)。

ここに行きます:

public static class SomeExtensions {

    private static readonly MethodInfo methodDefOf_PrivateHelper = typeof(SomeExtensions)
        .GetMethod("PrivateHelper", 
                   BindingFlags.NonPublic | BindingFlags.Static, 
                   Type.DefaultBinder, 
                   new [] { typeof(System.Collections.IEnumerable) }, 
                   null);

    private static IEnumerable<T> PrivateHelper<T>(System.Collections.IEnumerable @this){
        foreach (var @object in @this)
            yield return (T)@object; // right here is were you can get the cast exception
    }

    public static System.Collections.IEnumerable DynamicCast(
        this System.Collections.IEnumerable @this,
        Type elementType
    ) {
        MethodInfo particularizedMethod = SomeExtensions.methodDefOf_PrivateHelper
            .MakeGenericMethod(elementType);

        object result = particularizedMethod.Invoke(null, new object[] { @this });
        return result as System.Collections.IEnumerable;
    }


}

そして、これがあなたがそれを使うことができる方法です:

object[] someObjects = new object[] { "one", "two", "three" };
IEnumerable implicitlyCastedToEnumerable = someObjects;

Type unknownType = (DateTime.Now.Hour > 14) ? typeof(string) : typeof(int);

IEnumerable apparentlyNothingHappenedHere 
    = implicitlyCastedToEnumerable.DynamicCast(unknownType);

// if it's not after 14:00, then an exception would've jumped over this line and
// straight out the exit bracket or into some catch clause

// it it's after 14:00, then the apparentlyNothingHappenedHere enumerable can do this:
IEnumerable<string> asStrings = (IEnumerable<string>)apparentlyNothingHappenedHere;

// whereas the earlier would've cause a cast exception at runtime
IEnumerable<string> notGoingToHappen = (IEnumerable<string>)implicitlyCastedToEnumerable;
于 2013-03-02T16:16:14.070 に答える
0

拡張メソッドはすでに汎用です。コンストラクターを呼び出すだけです。

var list = new List<T>();

非ジェネリックIEnumerableをジェネリックIEnumerableに変換する場合は、System.Linqにそのためのメソッドが既にあります。

return list.Cast<T>();
于 2013-03-02T16:05:14.207 に答える
0

これはトリックをするかもしれません

public static IEnumerable<T> CreateEnumerable<T>(this IEnumerable list, Type type) {
    var stuff=something;

    var temp=stuff;
    stuff=Array.CreateInstance(type, count) as T[]; 
    // copy elements to stuff
    return stuff as IEnumerable<T>;
}

ただし、Tタイプが保証されるものはありませんtype。の署名を見てくださいCreateEnumerable<T>

public static IEnumerable<T> CreateEnumerable<T>(this IEnumerable list, Type type) 

Tどのジェネリックメソッドを呼び出すかを推測する引数からはありません。つまり、呼び出すときに型パラメーターを指定する必要があります。それは冗長だと思いますがT、むしろ

public static IEnumerable CreateEnumerable(this IEnumerable list, Type type) {
    var stuff=something;

    var temp=stuff;
    stuff=Array.CreateInstance(type, count);
    // copy elements to stuff
    return stuff as IEnumerable;
}

私はあなたが望んでいることを知らないことに注意してくださいcount

于 2013-03-02T17:19:59.443 に答える