C#はSystem.Typeをジェネリックパラメーターとして使用します


87

データベースで照会する必要のあるタイプのリスト(System.Type)があります。

このタイプごとに、次のextensionmethod(LinqToNhibernateの一部)を呼び出す必要があります。

Session.Linq<MyType>()

しかし、私はMyTypeを持っていませんが、代わりにTypeを使用したいと思います。

私が持っているものは:

System.Type typeOne;

しかし、私は以下を実行することはできません:

Session.Linq<typeOne>()

タイプをジェネリックパラメーターとして使用するにはどうすればよいですか?

回答:


95

直接はできません。ジェネリックスのポイントは、コンパイル時に関心のある型がわかっていて、その型のインスタンスを処理できる、コンパイル時の型の安全性を提供することです。あなたの場合、あなたは知ってTypeいるだけなので、あなたが持っているオブジェクトがそのタイプのインスタンスであるというコンパイル時のチェックを得ることができません。

リフレクションを介してメソッドを呼び出す必要があります-次のようなものです:

// Get the generic type definition
MethodInfo method = typeof(Session).GetMethod("Linq", 
                                BindingFlags.Public | BindingFlags.Static);

// Build a method with the specific type argument you're interested in
method = method.MakeGenericMethod(typeOne);
// The "null" is because it's a static method
method.Invoke(null, arguments);

このタイプを頻繁に使用する必要がある場合は、必要な他のジェネリックメソッドを呼び出す独自のジェネリックメソッドを作成してから、リフレクションを使用しメソッドを呼び出す方が便利な場合があります


1
リフレクションを使用してメソッドを呼び出すソリューションについて読みました。しかし、私は別の解決策があることを望みました。
1

invokeメソッドは「オブジェクト」を返します。正しいタイプにキャストするまで、このオブジェクトをクエリすることはできません。(おそらくIQueryable <T>になります)。オブジェクトを自分のタイプにキャストするにはどうすればよいですか?
1

3
@Jan:できません-しかし、コンパイル時に型がわからないため、その型も使用できません...これは、一般的なメソッドを作成する価値があるかもしれません。強く型付けされた方法で必要なすべてを実行し、それをリフレクションで呼び出します。あるいは、非ジェネリックIQueryableはあなたが必要とすることをしますか?
Jon Skeet 2011年

2
@Jon:ありがとう、私は自分のジェネリックメソッドを書いてみます。残念ながら、ジェネリックではないIqueryableは問題を解決しません。
1

1
@Jon:自分のジェネリックメソッドを使用して別のジェネリックメソッドを呼び出すと、問題が解決しました
1

30

これを行うには、リフレクションを使用する必要があります。

typeof(Session).GetMethod("Linq").MakeGenericMethod(typeOne).Invoke(null, null);

(それLinq<T>()が型の静的メソッドであると仮定しますSession

場合はSession、実際にあるオブジェクトは、あなたが場所を知る必要がありますLinq方法は、実際に宣言され、渡すSession引数として:

typeof(DeclaringType).GetMethod("Linq").MakeGenericMethod(typeOne)
     .Invoke(null, new object[] {Session});

1

リフレクションを介してジェネリックメソッドを呼び出す一般的なメソッドが1つあります

/// <summary>
    /// This method call your method through Reflection 
    /// so i wil call the method like CallGenericMethodThroughReflection<Session>(assemblyQualifiedName,Linq,false,new[] { file }) 
    /// </summary>
    /// <typeparam name="T">Call method from which file</typeparam>
    /// <param name="assemblyQualifiedName">Your can get assemblyQualifiedName like typeof(Payroll.Domain.Attendance.AttendanceApplicationMaster).AssemblyQualifiedName</param>
    /// <param name="methodName"></param>
    /// <param name="isStaticMethod"></param>
    /// <param name="paramaterList"></param>
    /// <param name="parameterType">pass parameter type list in case of the given method have overload  </param>
    /// <returns>return object of calling method</returns>
    public static object CallGenericMethodThroughReflection<T>(string assemblyQualifiedName, string methodName,bool isStaticMethod ,object[] paramaterList,Type[] parameterType = null)
    {
        try
        {
            object instance = null;
            var bindingAttr = BindingFlags.Static | BindingFlags.Public;
            if (!isStaticMethod)
            {
                instance = Activator.CreateInstance<T>();
                bindingAttr = BindingFlags.Instance | BindingFlags.Public;
            }
            MethodInfo MI = null;
            var type = Type.GetType(assemblyQualifiedName);
            if(parameterType == null)
                MI = typeof(T).GetMethod(methodName, bindingAttr);
            else
                MI = typeof(T).GetMethod(methodName, bindingAttr,null, parameterType, null);//this will work in most case some case not work
            if (type == null || MI == null) // if the condition is true it means given method or AssemblyQualifiedName entity not found
                return null;
            var genericMethod = MI.MakeGenericMethod(new[] { type });
            return genericMethod.Invoke(instance, paramaterList);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.