C # sử dụng System.Type làm tham số Chung


87

Tôi có một danh sách các loại (System.Type) cần được truy vấn trên cơ sở dữ liệu.

Đối với mỗi loại này, tôi cần gọi tiện ích mở rộng sau (là một phần của LinqToNhibernate):

Session.Linq<MyType>()

Tuy nhiên, tôi không có MyType, nhưng tôi muốn sử dụng Type.

Những gì tôi có là:

System.Type typeOne;

Nhưng tôi không thể thực hiện những điều sau:

Session.Linq<typeOne>()

Làm cách nào để sử dụng Loại làm tham số Chung?

Câu trả lời:


95

Bạn không thể, trực tiếp. Điểm chung chung là cung cấp sự an toàn cho kiểu thời gian biên dịch , nơi bạn biết kiểu mình quan tâm tại thời điểm biên dịch và có thể làm việc với các bản sao của kiểu đó. Trong trường hợp của bạn, bạn chỉ biết Typevì vậy bạn không thể nhận được bất kỳ kiểm tra thời gian biên dịch nào rằng bất kỳ đối tượng nào bạn có đều là bản sao của loại đó.

Bạn sẽ cần gọi phương thức thông qua phản chiếu - một cái gì đó như sau:

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

Nếu bạn cần sử dụng loại này nhiều, bạn có thể thấy thuận tiện hơn khi viết phương thức chung của riêng mình, phương thức này gọi bất kỳ phương thức chung nào khác mà nó cần, sau đó gọi phương thức của bạn với sự phản chiếu.


1
Tôi đã đọc về một giải pháp sử dụng phản xạ để gọi phương thức. Nhưng tôi hy vọng có một giải pháp khác.
Jan

phương thức gọi trả về một "Đối tượng". Tôi không thể truy vấn đối tượng này cho đến khi tôi truyền nó đến đúng Loại. (Có thể sẽ là IQueryable <T>). Làm cách nào để tôi có thể truyền đối tượng về kiểu tôi có?
Ngày

3
@Jan: Bạn không thể - nhưng sau đó bạn cũng sẽ không thể sử dụng kiểu đó, bởi vì bạn không biết kiểu tại thời điểm biên dịch ... đây là nơi có thể đáng để bạn viết một phương thức chung thực hiện mọi thứ bạn muốn theo cách được đánh máy mạnh mẽ và gọi điều đó bằng sự phản ánh. Ngoài ra, người không chung chung có IQueryablelàm những gì bạn cần không?
Jon Skeet

2
@Jon: Cảm ơn, tôi sẽ thử viết phương pháp chung của riêng mình. Rất tiếc, Iqueryable không chung chung sẽ không giải quyết được vấn đề.
Ngày

1
@ Jon: sử dụng phương pháp chung của riêng tôi để gọi một phương pháp chung giải quyết vấn đề
Jan

30

Để làm điều này, bạn cần sử dụng phản chiếu:

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

(giả sử đó Linq<T>()là một phương thức tĩnh trên kiểu Session)

Nếu Sessionthực sự là một đối tượng , bạn sẽ cần biết Linqphương thức thực sự được khai báo ở đâu và chuyển vào Sessiondưới dạng đối số:

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

1

Tôi có một phương pháp chung gọi là Phương pháp Chung Gọi qua Phản ánh

/// <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;
        }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.