[C#] TypeLoadException에 ‘구현되지 않음’이 표시되지만 구현되었습니다.

테스트 시스템에 매우 이상한 버그가 있습니다. 오류는 다음과 같습니다

System.TypeLoadException: Method 'SetShort' in type 'DummyItem' from assembly 'ActiveViewers (...)' does not have an implementation.

이유를 이해할 수 없습니다. SetShort에서이 DummyItem클래스 및 난 단지 확인이 문제를 버전 배포 / 아니라고 확인하기 위해 이벤트 로그에 쓰기로 버전을 다시 컴파일했습니다. 이상한 점은 호출 코드가 SetShort메소드를 호출하지도 않는다는 것 입니다.



답변

참고 -이 답변이 도움이되지 않으면 시간을내어 사람들이 추가 한 다른 답변을 아래로 스크롤하십시오.

짧은 답변

한 어셈블리의 인터페이스에 메소드를 추가 한 다음 다른 어셈블리의 구현 클래스에 메소드를 추가하지만 새 버전의 인터페이스 어셈블리를 참조하지 않고 구현 어셈블리를 재 구축하는 경우에 발생할 수 있습니다.

이 경우 DummyItem은 다른 어셈블리의 인터페이스를 구현합니다. SetShort 메서드는 최근 인터페이스와 DummyItem에 모두 추가되었지만 DummyItem을 포함하는 어셈블리는 이전 버전의 인터페이스 어셈블리를 참조하여 다시 작성되었습니다. 따라서 SetShort 메소드는 효과적으로 존재하지만 매직 소스가 없으면 인터페이스의 동등한 메소드에 연결됩니다.

긴 대답

이 문제를 재현하려면 다음을 시도하십시오.

  1. 클래스 라이브러리 프로젝트를 작성하십시오. InterfaceDef, 하나의 클래스 만 추가하고 빌드하십시오.

    public interface IInterface
    {
        string GetString(string key);
        //short GetShort(string key);
    }
  2. 두 번째 클래스 라이브러리 프로젝트를 만듭니다 (구현 (별도의 솔루션 사용), InterfaceDef.dll을 프로젝트 디렉토리에 복사하고 파일 참조로 추가, 하나의 클래스 만 추가, 빌드)

    public class ImplementingClass : IInterface
    {
        #region IInterface Members
        public string GetString(string key)
        {
            return "hello world";
        }
    
        //public short GetShort(string key)
        //{
        //    return 1;
        //}
        #endregion
    }
  3. 세 번째 콘솔 프로젝트 인 ClientCode를 작성하고 두 개의 dll을 프로젝트 디렉토리에 복사 한 후 파일 참조를 추가하고 다음 코드를 Main 메소드에 추가하십시오.

     IInterface test = new ImplementingClass();
     string s = test.GetString("dummykey");
     Console.WriteLine(s);
     Console.ReadKey();
  4. 코드를 한 번 실행하면 콘솔에 “hello world”라고 표시됩니다

  5. 두 개의 dll 프로젝트에서 코드의 주석 처리를 제거하고 다시 빌드하십시오. 두 개의 dll을 ClientCode 프로젝트로 다시 복사 한 후 다시 빌드하고 다시 시도하십시오. ImplementingClass를 인스턴스화하려고 할 때 TypeLoadException이 발생합니다.


답변

asker 자신의 답변에서 이미 언급 한 것 외에도 다음을 주목할 가치가 있습니다. 이것이 발생하는 이유는 클래스가 해당 메소드를 구현하지 않고 인터페이스 메소드와 동일한 서명을 가진 메소드를 가질 수 있기 때문입니다. 다음 코드는이를 보여줍니다.

public interface IFoo
{
    void DoFoo();
}

public class Foo : IFoo
{
    public void DoFoo() { Console.WriteLine("This is _not_ the interface method."); }
    void IFoo.DoFoo() { Console.WriteLine("This _is_ the interface method."); }
}

Foo foo = new Foo();
foo.DoFoo();               // This calls the non-interface method
IFoo foo2 = foo;
foo2.DoFoo();              // This calls the interface method


답변

내 응용 프로그램에 오류 메시지의 메소드가 사용하는 클래스를 정의하는 다른 어셈블리에 대한 참조가 없을 때 이것을 얻었습니다. PEVerify를 실행하면 “시스템이 지정된 파일을 찾을 수 없습니다.”라는 오류가 발생했습니다.


답변

나는 같은 메시지를 보았고 여기에 우리가 발견 한 것이 있습니다 : 우리는 프로젝트에서 타사 dll을 사용합니다. 새로운 릴리스가 나온 후 우리는 새로운 dll 세트를 가리 키도록 프로젝트를 변경하고 성공적으로 컴파일했습니다.

런타임 중에 인터페이스 클래스 중 하나를 설치하려고 할 때 예외가 발생했습니다. 우리는 다른 모든 참조가 최신 상태인지 확인했지만 여전히 운이 없습니다. 오류 메시지에서 메소드의 리턴 유형이 참조되지 않은 새 어셈블리의 완전히 새로운 유형이라는 것을 발견하기 위해 (오브젝트 브라우저 사용) 잠시 시간이 필요했습니다.

어셈블리에 대한 참조를 추가했는데 오류가 사라졌습니다.

  • 오류 메시지는 오해의 소지가 있었지만 올바른 방향 (올바른 방법, 잘못된 메시지)을 다소 가리 켰습니다.
  • 문제의 방법을 사용하지 않았지만 예외가 발생했습니다.
  • 어떤 질문이 나에게로 이어질까요 : 어떤 경우 에이 예외가 발생하면 컴파일러가 왜 그것을 선택하지 않습니까?

답변

다음 시나리오에서이 오류가 발생했습니다.

  • 어셈블리 A와 B 모두 System.Web.Mvc 버전 3.0.0.0을 참조했습니다.
  • 어셈블리 A는 어셈블리 B를 참조했으며 System.Web.Mvc에서 클래스를 반환하는 메서드를 사용하여 어셈블리 B의 인터페이스를 구현 한 클래스를 가졌습니다.
  • 어셈블리 A가 System.Web.Mvc 버전 4.0.0.0으로 업그레이드 됨
  • 어셈블리 C는 아래 코드를 실행했습니다 (FertPin.Classes.Contact는 어셈블리 A에 포함됨).

var target = Assembly.GetAssembly(typeof(FertPin.Classes.Contact));

나를위한 수정은 어셈블리 B의 System.Web.Mvc 참조를 4.0.0.0으로 업그레이드하는 것입니다. 지금 분명해 보인다!

원래 포스터 덕분에!


답변

다른 경우에는이 버전의 서명 된 어셈블리가 잘못된 경우이 오류가 발생할 수 있습니다. 이 원인에 대한 일반적인 증상은 아니지만 여기에있는 시나리오가 있습니다.

  • asp.net 프로젝트에는 어셈블리 A와 어셈블리 B가 포함되며 B는 강력하게 이름이 지정됩니다.

  • 어셈블리 A는 Activator.CreateInstance를 사용하여 어셈블리 C를로드합니다 (즉, 별도로 빌드 된 C에 대한 참조가 없음)

  • C는 현재 존재하는 것보다 이전 버전의 어셈블리 B를 참조하여 빌드되었습니다.

누군가에게 도움이되기를 바랍니다-이것을 알아내는 데 오랜 시간이 걸렸습니다.


답변

이 오류도 발생했으며 x86 어셈블리를 참조하는 모든 CPU 어셈블리를 참조하는 모든 CPU exe에 의해 발생했습니다.

예외는 MyApp.Interfaces (Any CPU)를 파생시키는 MyApp.Implementations (Any CPU)의 클래스에 대한 메소드에 대해 불평했지만 fuslogvw.exe에서 MyApp의 숨겨진 ‘잘못된 형식으로 프로그램을로드하려고 시도했습니다’예외를 발견했습니다. .CommonTypes (x86) 둘 다 사용됩니다.