C # Genel parametre olarak System.Type kullanın


89

Veritabanında sorgulanması gereken türlerin bir listesi (System.Type) var.

Bu türlerin her biri için aşağıdaki uzantı yöntemini çağırmam gerekiyor (LinqToNhibernate'in bir parçası):

Session.Linq<MyType>()

Ancak MyType'a sahip değilim, bunun yerine bir Tür kullanmak istiyorum.

Sahip olduğum şey:

System.Type typeOne;

Ama şunu yapamıyorum:

Session.Linq<typeOne>()

Bir Türü Genel parametre olarak nasıl kullanabilirim?

Yanıtlar:


95

Doğrudan yapamazsınız. Jeneriklerin amacı, derleme zamanında ilgilendiğiniz türü bildiğiniz ve bu tür örneklerle çalışabileceğiniz derleme zamanı tür güvenliği sağlamaktır . Sizin durumunuzda, yalnızca, Typesahip olduğunuz nesnelerin bu türden örnekler olduğuna dair herhangi bir derleme zamanı denetimi alamayacağınızı bilirsiniz .

Yöntemi yansıtma yoluyla çağırmanız gerekecek - bunun gibi bir şey:

// 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);

Bu türü çok kullanmanız gerekiyorsa, ihtiyaç duyduğu diğer genel yöntemleri çağıran kendi genel yönteminizi yazmayı ve ardından kendi yönteminizi yansıma ile çağırmayı daha uygun bulabilirsiniz .


1
Yöntemi çağırmak için yansımayı kullanan bir çözüm hakkında okudum. Ama başka bir çözüm olmasını umuyordum.
Jan

invoke yöntemi bir "Object" döndürür. Doğru Türe dönüşene kadar bu nesneyi sorgulayamıyorum. (Muhtemelen IQueryable <T> olacaktır). Nesneyi sahip olduğum türe nasıl dönüştürebilirim?
Jan

3
@Jan: Yapamazsınız - ama o zaman bu türü de kullanamazsınız, çünkü türü derleme sırasında bilmiyorsunuz ... burası genel bir yöntem yazmaya değer olabilir. istediğiniz her şeyi güçlü yazılmış bir şekilde yapar ve bunu derinlemesine düşünerek çağırır . Alternatif olarak, jenerik olmayan IQueryableihtiyacınız olanı yapıyor mu?
Jon Skeet

2
@Jon: Teşekkürler, kendi genel yöntemimi yazmaya çalışacağım. Maalesef jenerik olmayan sorgulanabilir sorun çözülmez.
Jan

1
@Jon: Başka bir jenerik yöntemi çağırmak için kendi jenerik yöntemi kullanarak sorunu çözüldü
Jan

30

Bunu yapmak için yansıma kullanmanız gerekir:

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

( Linq<T>()tür üzerinde statik bir yöntem olduğunu varsayarak Session)

Eğer Sessionbir aslında nesne , nereye bilmek gerekir Linqyöntem aslında bildirilmiş ve geçmek Sessionbağımsız değişken olarak:

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

1

Yansıma Üzerinden Genel Yöntemi çağıran genel bir yöntemim var

/// <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;
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.