C #은 System.Type을 Generic 매개 변수로 사용합니다.


87

데이터베이스에서 쿼리해야하는 유형 (System.Type) 목록이 있습니다.

이 유형 각각에 대해 다음 확장 메서드 (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 메소드는 "Object"를 리턴합니다. 올바른 유형으로 캐스트 할 때까지이 개체를 쿼리 할 수 ​​없습니다. (아마도 IQueryable <T>). 객체를 내가 가진 유형으로 어떻게 캐스팅 할 수 있습니까?
1

3
@Jan : 당신은 할 수 없습니다-하지만 컴파일 타임에 타입을 모르기 때문에 그 타입도 사용할 수 없을 것입니다 ... 이것은 당신이 제네릭 메소드를 작성하는 것이 가치가있는 곳입니다. 강력한 형식으로 원하는 모든 것을 수행 하고이를 반영 하여 호출 합니다 . 또는 비 제네릭 IQueryable이 필요한 작업을 수행합니까?
Jon Skeet 2011 년

2
@Jon : 감사합니다. 제 고유 한 방법을 작성해 보겠습니다. 불행히도 제네릭이 아닌 Iqueryable은 문제를 해결할 수 없습니다.
1

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

반사를 통해 일반 메서드 호출을 호출하는 일반적인 메서드가 하나 있습니다.

/// <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.