COM 제한 사항을 염두에두고 .NET 라이브러리를 작성하거나 .NET 라이브러리를 Interop과 분리하는 것이 더 좋습니까?


9

나는이 흥미로운 기사를 보았습니다 : CodeProject에서 COM 상호 운용성을 사랑하는 방법은 무엇입니까?

저자는 .NET 라이브러리의 아름다움을 없애기 때문에 .NET 라이브러리에서 COM 요소를 원하지 않는다고 주장합니다. 대신 .NET 라이브러리를 COM에 공개하는 별도의 Interop 라이브러리를 작성하려고합니다. 이 Interop 라이브러리는 COM이 매개 변수, 오버로드 된 메서드, 제네릭, 상속, 정적 메서드 등을 가진 생성자를 지원하지 않는다는 사실을 처리합니다.

그리고 그것이 매우 참신하다고 생각하지만, 단지 프로젝트를 반영하지 않습니까?

  • 이제 .NET 라이브러리와 Interop 라이브러리를 단위 테스트해야합니다.
  • 이제 아름다운 .NET 라이브러리를 해결하고 COM에 노출시키는 방법을 알아내는 데 시간을 투자해야합니다.
  • 수업 수를 효과적으로 두 배 또는 세 배로 늘려야합니다.

COM과 비 COM을 모두 지원하기 위해 라이브러리가 필요한지 확실히 이해할 수 있습니다. 그러나 COM 만 사용하려는 경우 이러한 종류의 디자인으로 볼 수없는 이점이 있습니까? C # 언어의 장점 만 얻습니까?

아니면 래퍼를 제공하여 라이브러리 버전을 쉽게 만들 수 있습니까? COM을 사용하지 않아도 단위 테스트가 더 빨리 실행됩니까?


2
유용한 도구를 사용하여 실제 코드를 더 좋게 / 더 깨끗하게 만들 수 있다는 것 외에? 그리고 아마도 (레거시 레거시) COM 항목에 대한 명확한 마이그레이션 경로를 제공합니까?
Telastyn

3
이것은 전체 네임 스페이스에 대해 큰 쓰기 패턴과 같습니다. .NET 기능을 사용하고 싶지만 실제로 OLE 자동화가 필요한 경우 이와 같이 구성하는 것이 현명하다고 생각합니다. COM 래퍼는 기본적으로 현대적인 (불변의? 일반?) 관용구를 매개 변수가없는 생성자, 크게 변경 가능한 객체 및 일반 목록에 대한 SAFEARRAY가있는 오래된 COM 객체로 변환하는 것입니다. 다른 .NET 구성 요소를 지원하거나 완전히 새로운 스타일에 관심이 있다면 이것이 의미가 있습니다. COM 만 지원하는 경우 VB6 (32 비트)로 전체 내용을 작성하고 하나의 관용구 만 유지하는 것이 어떻습니까?
Mike

3
@MasonWheeler : 6 개월 이상 된 모든 소프트웨어가 "레거시"와 같은 방식으로 더 이상 사용되지 않습니다. 맞습니까?
whatsisname

2
@MasonWheeler COM은 프로세스를 벗어나는 것을 제어하는 ​​최선의 선택이기 때문에 Microsoft (일부 그룹의 일부 그룹 포함)가 원하는 사람 수에 관계없이 감가 상각 할 수 없습니다.
Mike

2
@Mike, 실제로 VB6 프로젝트를 C # .NET으로 이식하려고합니다. 우리가 사용하는 사용자 대면 API는 매우 간단하지만 장면 뒤의 코드는 그대로 유지 관리 할 수 ​​없습니다. C # .NET에서 대부분의 라이브러리를 구현하고 다양한 클래스와 상호 작용하는 간단한 API를 제공하는 Interop Facade를 제공하고 싶습니다.
robodude666

답변:


7

그러나 COM 만 사용하려는 경우 이러한 종류의 디자인으로 볼 수없는 이점이 있습니까?

이 질문 스 니펫은 여기에서 디자인 결정 가장 중요한 부분이며, 그 대답은 항상 그렇습니다 .

COM Interop을 통해서만 라이브러리를 사용하려는 경우이를 염두에두고 전체 시스템을 설계해야합니다. 줄 수를 세 배로 늘릴 이유가 없습니다. 시스템에 LoC가 많을수록 더 많은 결함이 발생합니다. 따라서 COM 호환 기능 만 사용하도록 시스템을 설계해야합니다.

그러나 .Net 라이브러리의 사용을 COM으로 제한 해야하는 좋은 이유는 생각할 수 없습니다. 다른 .Net 코드에서 어셈블리를 사용하고 싶지 않은 이유는 무엇 입니까? 이런 식으로 자신을 제한하는 것은 거의 의미가 없습니다.

이에 대한 경험이 있으므로 처리 방법을 알려 드리겠습니다. 확실히 이상적이지 않습니다. 나는 약간의 절충안을 만들었습니다. 최신 .Net 관용구와 호환되지 않는 COM 클래스 (실제로 인터페이스)의 외관 만 사용합니다. 그렇지 않으면 .Net 인터페이스를 COM에 직접 노출시킵니다. 이것은 기본적으로 제네릭을 사용하는 모든 인터페이스에 파사드를 사용한다는 것을 의미합니다. 내가 만난 것은 제네릭 뿐이며 단순히 호환되지 않습니다. 불행히도, 이것은을 반환하는 모든 것에 대한 정면을 의미하며 IEnumerable<T>, 이는 매우 일반적입니다.

그러나 파사드 클래스는 .Net 클래스에서 상속하고 특정 Interop 인터페이스를 구현하기 때문에 이것은 거의 나쁘지 않습니다. 이 같은.

namespace Company.Product.Feature
{
    public class MyClass : INetInterface 
    {
        // lots of code
    }
}

namespace Company.Product.Interop
{
    public class MyClass : Feature.MyClass, IComInterface
    {
        // over ride only the  incompatible properties/methods
    }
}

이렇게하면 중복 코드가 최소한으로 유지되고 COM 인터페이스가 "의도하지 않은"변경으로부터 보호됩니다. 코어 클래스 / 인터페이스가 변경됨에 따라 어댑터 클래스는 더 많은 메소드를 능가해야합니다 (또는 인터페이스를 중단하고 주요 버전 번호를 충돌시킵니다). 반면, 모든 Interop 코드가 Interop네임 스페이스에 저장되는 것은 아니며 파일 구성이 혼동 될 수 있습니다. 내가 말했듯이, 그것은 트레이드 오프입니다.

이에 대한 전체 예를 보려면 내 repo 의 SourceControlInterop 폴더를 찾아 볼 수 있습니다 . ISourceControlProvider그리고 GitProvider특히 관심이 될 것입니다.


@RubberDuck 응답에 감사드립니다! 며칠 전에 RubberDuck 프로젝트를 뛰어 다녔습니다. 코드를 읽는 것은 매우 흥미로 웠습니다. IEnumerableVBA 에 합격 할 수 있습니까? 또한 Rubberduck.Interop.GitProviderCOM에서 지원하지 않는 경우 매개 변수화 된 생성자를 정의한 이유는 무엇입니까?
robodude666

그렇습니다. IEnumerableCOM을 통과 할 수 는 있지만 이전 버전이 아닌 일반 버전이어야합니다. 생성자에 대해서는를 살펴보십시오 SourceControlClassFactory. 기본적으로 ctor에 매개 변수가 필요하지 않은 클래스의 인스턴스를 초기화하고 API 클래스의 새 인스턴스에 액세스하는 데 사용하여 가짜로 만듭니다.
RubberDuck

ComVisible(true)COM이 지원하지 않는 클래스 / 인터페이스에 정의 된 내용 은 단순히 "무시"된 것 같습니다. 또한 여러 네임 스페이스에 동일한 이름의 클래스가 정의되어 ProgId있는지 또는 둘 이상의 노출을 원할 경우 고유 한 클래스를 제공해야한다고 추측 하고 있습니까?
robodude666

예. 맞고 static방법은 무시됩니다. VB_PredeclaredId사용 가능한 VB6과 동등한 제품이 있는지 확인하려고 합니다. 기본 인스턴스를 만들 있다고 생각합니다 .
RubberDuck

7

.NET 라이브러리의 아름다움에서 벗어납니다.

그 작가는 얼굴에 눈을 뜨다 때려야한다. 모든 전문 프로젝트의 목표는 사람들이 사용하기 원하는 소프트웨어를 만드는 것입니다. 아름다움에 대한 오해의 이상은 오래지 않아 왔습니다. 그것이 유일한 추론이라면, 저자는 모든 신뢰성을 잃어 버렸습니다.

클래스를 공용으로 표시하고 COM을 통해 .NET 코드와 대화 할 수 있다는 것은 매우 유용합니다. 아름다움을위한 생산성에 대한 큰 이점은 미쳤다는 것을 버립니다.

그러나 COM을 사용하여 작동하게하려면 몇 가지 절충이 필요하며 인수가없는 생성자가 필요하고 언급 한 다른 요소 중 하나가 필요합니다. 만약 이것들이 당신이 사용하지 않는 기능이거나, 사용하지 않기 위해 당신을 다치게하지 않는다면, COM과 비 COM에 같은 클래스를 사용함으로써 많은 작업이 저장 될 것입니다.

반면, COM 클라이언트가 극도로 다른 인터페이스를 기대하거나 .NET 클래스에서 다루기 어려운 종속성 또는 기타 제한 사항이 있거나 .NET 클래스를 크게 변경하고 COM을 계속 유지해야 할 경우 그런 다음 호환성을 보장하기 위해 Interop 클래스를 만들어 해당 간격을 메 웁니다.

그러나 "아름다움"에 대해서는 생각하지 마십시오. .NET을 통해 COM을 노출 할 수 있다는 것은 작업을 절약하기위한 것입니다. 자신을 위해 더 많은 작품을 만들지 마십시오.


+1. 나는 블랙 박스블랙 버튼 의 아름다움을 좋아하지만 실용성이 훨씬 중요합니다.
gbjbaanb

실제로이 토론에 "아름다움"이라는 용어를 도입 한 사람은 깨우기 기능이 필요할 수 있으며, 이는 다른 기사의 저자가 아닙니다.
Doc Brown

2
참고로 현재 생성자에 인수가 필요한 경우 기존 인터페이스 / API를 다시 디자인하는 대신 COM 구성 요소에 클래스 팩토리를 제공하는 것이 가장 좋습니다.
RubberDuck

1
팩토리를 "GlobalMultiUse"클래스로 노출 할 수 있습니까? 따라서 Set oObject = MyCOMInterop.NewMyClass()먼저 새로운 팩토리 객체를 인스턴스화 하지 않고도 할 수 있습니까?
robodude666

그거 좋은 질문 @ robodude666입니다. 당신이 그것을 언급 했으므로 , 나는 그렇게 희망 합니다.
RubberDuck

3

글쎄요, 그 기사의 원저자는 기사의 어느 부분에서나 "아름다움"이라는 단어를 사용하지 않았습니다. 그들 자신.

이 기사를 이해 한 한 .NET 라이브러리는 이미 존재했으며 COM을 염두에두고 작성되지 않았습니다. 아마도 라이브러리를 만들 때 COM을 지원할 필요가 없었기 때문일 것입니다.

나중에 COM 지원에 대한 추가 요구 사항이 도입되었습니다. 이러한 상황에 직면하면 두 가지 옵션이 있습니다.

  • COM interop과 호환되도록 원래 lib를 다시 디자인하십시오 (물리를 깰 위험이 있음)

  • 원래 작업 라이브러리를 대부분 그대로두고 대신 "래퍼"(또는 "어댑터") 기능을 사용하여 별도의 어셈블리를 만듭니다.

랩퍼 또는 어댑터를 작성하는 것은 잘 알려진 디자인 패턴 (또는이 경우에는 더 많은 아키텍처 패턴)이며 장단점도 잘 알려져 있습니다. 그것에 대한 한 가지 주장은 더 나은 "문제의 분리"이며, 그것은 아름다움과 관련이 없습니다.

당신의 걱정에

이제 .NET 라이브러리와 Interop 라이브러리를 단위 테스트해야합니다.

재 설계하여 COM 인터페이스를 기존 .NET 라이브러리에 도입 할 때 해당 인터페이스를 테스트해야합니다. 수동으로 작성된 어댑터를 소개하려면 인터페이스가 작동중인 추가 테스트가 필요할 수 있지만 lib의 핵심 비즈니스 기능에 대한 모든 단위 테스트를 복사 할 필요는 없습니다. 그것이 lib에 대한 또 다른 인터페이스라는 것을 잊지 마십시오.

이제 아름다운 .NET 라이브러리를 해결하고 COM에 노출시키는 방법을 알아내는 데 시간을 투자해야합니다.

원래 라이브러리를 다시 디자인해야 할 때도 알아 내야하며 훨씬 더 많은 작업이 필요합니다.

수업 수를 효과적으로 두 배 또는 세 배로 늘려야합니다.

공용 COM 인터페이스를 통해 노출되는 클래스 (원래 라이브러리의 일부 클래스 수) 여야합니다.

언급 한 다른 상황에서 COM을 처음부터 일류 시민으로 지원해야한다는 것을 이미 알고있을 때, 나는 당신이 맞다고 생각합니다. 별도의 어댑터 lib를 추가하는 번거 로움을 없애고 COM 지원 직접 .NET lib.


(+1) 그러나 "... 원본 라이브러리 중 적은 수 여야합니다 ..."는 사실 일뿐입니다. "클래스 라이브러리 스타일"로 설계된 많은 유형의 프로젝트가 있으며, 여기서 하나의 클래스는 하나의 공개 된 목적과 같으며 해당 클래스는 흥미로운 기능을 제공하도록 구성됩니다. 이 경우 .NET 클래스 수와 COM interop 클래스 수간에 일대일 매핑이있을 수 있습니다.
rwong
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.