[.net] Assembly.GetTypes () 호출시 ReflectionTypeLoadException을 방지하는 방법

다음과 유사한 코드를 사용하여 특정 인터페이스를 구현하는 형식에 대한 어셈블리를 스캔하려고합니다.

public List<Type> FindTypesImplementing<T>(string assemblyPath)
{
    var matchingTypes = new List<Type>();
    var asm = Assembly.LoadFrom(assemblyPath);
    foreach (var t in asm.GetTypes())
    {
        if (typeof(T).IsAssignableFrom(t))
            matchingTypes.Add(t);
    }
    return matchingTypes;
}

내 문제는, 예를 들어 어셈블리에 현재 사용할 수없는 어셈블리를 참조하는 유형이 포함되어있는 경우와 같이 어떤 경우에 ReflectionTypeLoadException호출 할 때 내가 얻는 것 asm.GetTypes()입니다.

제 경우에는 문제를 일으키는 유형에 관심이 없습니다. 검색중인 유형에는 사용할 수없는 어셈블리가 필요하지 않습니다.

문제는 예외를 발생시키는 유형을 어떻게 든 건너 뛰거나 무시할 수 있지만 어셈블리에 포함 된 다른 유형은 계속 처리 할 수 ​​있습니까?



답변

상당히 불쾌한 방법은 다음과 같습니다.

Type[] types;
try
{
    types = asm.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
    types = e.Types;
}
foreach (var t in types.Where(t => t != null))
{
    ...
}

그래도 이것을해야하는 것은 확실히 성가신 일입니다. 확장 메서드를 사용하여 “클라이언트”코드에서 더 멋지게 만들 수 있습니다.

public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
    // TODO: Argument validation
    try
    {
        return assembly.GetTypes();
    }
    catch (ReflectionTypeLoadException e)
    {
        return e.Types.Where(t => t != null);
    }
}

return성명을 catch 블록 밖으로 옮기고 싶을 수도 있습니다. 저도 거기에있는 것을별로 좋아하지는 않지만 아마도 가장 짧은 코드 일 것 입니다 .


답변

어느 시점에서 ReflectionTypeLoadException을 수신하지 않고는 아무것도 할 수없는 것처럼 보이지만, 위의 답변은 예외에서 제공된 유형을 활용하려는 시도가 유형을로드하지 못하도록 만든 원래 문제에 여전히 문제를 제공한다는 점에서 제한적입니다.

이를 극복하기 위해 다음 코드는 어셈블리 내에있는 유형으로 유형을 제한하고 조건자가 유형 목록을 추가로 제한 할 수 있도록합니다.

    /// <summary>
    /// Get the types within the assembly that match the predicate.
    /// <para>for example, to get all types within a namespace</para>
    /// <para>    typeof(SomeClassInAssemblyYouWant).Assembly.GetMatchingTypesInAssembly(item => "MyNamespace".Equals(item.Namespace))</para>
    /// </summary>
    /// <param name="assembly">The assembly to search</param>
    /// <param name="predicate">The predicate query to match against</param>
    /// <returns>The collection of types within the assembly that match the predicate</returns>
    public static ICollection<Type> GetMatchingTypesInAssembly(this Assembly assembly, Predicate<Type> predicate)
    {
        ICollection<Type> types = new List<Type>();
        try
        {
            types = assembly.GetTypes().Where(i => i != null && predicate(i) && i.Assembly == assembly).ToList();
        }
        catch (ReflectionTypeLoadException ex)
        {
            foreach (Type theType in ex.Types)
            {
                try
                {
                    if (theType != null && predicate(theType) && theType.Assembly == assembly)
                        types.Add(theType);
                }
                // This exception list is not exhaustive, modify to suit any reasons
                // you find for failure to parse a single assembly
                catch (BadImageFormatException)
                {
                    // Type not in this assembly - reference to elsewhere ignored
                }
            }
        }
        return types;
    }


답변

Assembly.ReflectionOnlyLoad 를 고려해 보셨습니까 ? 당신이하려는 일을 고려하면 충분할 수 있습니다.


답변

제 경우에는 응용 프로그램 폴더에 원치 않는 어셈블리가 있기 때문에 동일한 문제가 발생했습니다. Bin 폴더를 지우고 응용 프로그램을 다시 빌드하십시오.


답변