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


97

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

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()입니다.

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

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


1
찾고있는 것보다 훨씬 더 많은 재 작성일 수 있지만 MEF는 유사한 기능을 제공합니다. 구현하는 인터페이스를 지정하는 [Export] 태그로 각 클래스를 표시하기 만하면됩니다. 그런 다음 당시에 관심이있는 인터페이스 만 가져올 수 있습니다.
Dirk Dastardly

@Drew, 귀하의 의견에 감사드립니다. MEF를 사용하려고 생각했지만 더 저렴한 다른 솔루션이 있는지 확인하고 싶었습니다.
M4N

플러그인 클래스 팩토리에 잘 알려진 이름을 지정하여 Activator.CreateInstance ()를 직접 사용할 수 있도록하는 것은 간단한 해결 방법입니다. 그럼에도 불구하고 어셈블리 해결 문제로 인해이 예외가 발생하면 나중에 발생할 수도 있습니다.
Hans Passant 2011 년

1
@ 한스 : 내가 완전히 이해하고 있는지 잘 모르겠습니다. 내가 스캔하는 어셈블리에는 주어진 인터페이스를 구현하는 여러 유형이 포함될 수 있으므로 잘 알려진 유형이 하나도 없습니다. (또한 : 하나뿐 아니라 둘 이상의 어셈블리를 스캔하고 있습니다)
M4N

2
거의 같은 코드와 같은 문제가 있습니다. 그리고 내가 탐색하는 어셈블리는에 의해 제공됩니다 AppDomain.CurrentDomain.GetAssemblies(). 이것은 내 컴퓨터에서는 작동하지만 다른 컴퓨터에서는 작동하지 않습니다. 도대체 왜 내 실행 파일의 일부 어셈블리를 읽을 수 없거나로드 할 수 없습니까?
v.oddou

답변:


130

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

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 블록 밖으로 옮기고 싶을 수도 있습니다. 저도 거기에있는 것을별로 좋아하지는 않지만 아마도 가장 짧은 코드 일 것 입니다 .


2
고마워요, 그것은 해결책 인 것 같습니다 (그리고 나는 그것이 깨끗한 해결책이 아니라는 것에 동의합니다).
M4N

4
이 솔루션은 예외에 노출 된 유형 목록을 사용하려고 할 때 여전히 문제가 있습니다. 유형로드 예외, FileNotFound, BadImage 등의 이유가 무엇이든 문제가있는 유형에 대한 모든 액세스가 계속 발생합니다.
sweetfa 2010 년

@sweetfa : 예, 매우 제한적입니다.하지만 예를 들어 OP가 이름 만 찾아야한다면 괜찮습니다.
Jon Skeet

1
재미있게도,이 포스트는 여기에 인용됩니다. 아주 흥미 롭습니다 : haacked.com/archive/2012/07/23/…
anhoppe

@sweetfa 반환 된 유형에 대한 FileNotFound 예외 문제를 방지하기 위해 수행 From t As Type In e.Types Where (t IsNot Nothing) AndAlso (t.TypeInitializer IsNot Nothing)하는 작업입니다. 잘 작동하는 것 같습니다.
ElektroStudios

22

어느 시점에서 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;
    }

4

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


2
예, 저는 그것을 고려했습니다. 그러나 그렇지 않으면 종속성을 수동으로로드해야하기 때문에 사용하지 않았습니다. 또한 코드는 ReflectionOnlyLoad로 실행할 수 없습니다 (링크 한 페이지의 설명 섹션 참조).
M4N

3

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.