C# 如何在单独的库中声明相同的接口

C# 如何在单独的库中声明相同的接口,c#,interface,com,directshow,C#,Interface,Com,Directshow,我需要在多个程序集中声明相同的接口,但不能引用公共库 我对接口有相同的定义,但当我尝试从另一个应用程序创建接口实例时,出现了以下错误: 无法将“myFilter”类型的对象强制转换为 “DirectShow.IBaseFilter” (myFilter的声明类似于:公共类myFilter:DirectSow.IBaseFilter…) 使用RegAsm.exe注册源对象 两个程序集都有以下声明: [ComImport, System.Security.SuppressUnmanagedCodeS

我需要在多个程序集中声明相同的接口,但不能引用公共库

我对接口有相同的定义,但当我尝试从另一个应用程序创建接口实例时,出现了以下错误:

无法将“myFilter”类型的对象强制转换为 “DirectShow.IBaseFilter”

(myFilter的声明类似于:
公共类myFilter:DirectSow.IBaseFilter…

使用RegAsm.exe注册源对象

两个程序集都有以下声明:

[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
Guid("56a86895-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IBaseFilter : IMediaFilter
...
代码被复制,因此
IMediaFilter
和所有其他声明完全相同

我尝试使用以下方法创建对象的实例:

 Type type = Type.GetTypeFromCLSID(new Guid("A3927399-E3AE-41E2-B094-0EA815CC9B9C"));
 IBaseFilter filter = (IBaseFilter)Activator.CreateInstance(type);

如何跨程序集强制转换对象?

根据定义:不能。两个彼此无关的独立接口永远不会是彼此之间的关系,即使它们具有“相同”的命名和相同的成员

专业解决方案是在独立程序集中分离接口,然后根据需要引用此程序集。所有其他的都被认为是黑客行为(在C#/.NET中)

要在此特定情况下应用所述解决方案,您需要2或3个组件:

汇编#1:(它“定义”接口)。此“定义”是一个COM接口,在这种特殊情况下:

 [ComImport, System.Security.SuppressUnmanagedCodeSecurity,
 Guid("56a86895-0ad4-11ce-b03a-0020af0ba770"),
 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
 public interface IBaseFilter : IMediaFilter
装配#2: 引用程序集#1,并包含一个实现接口的类

装配#3: 引用程序集#1和#2,可以访问和使用/强制转换程序集#2中的类。不要在此处(重新)导入接口。对于.NET来说,这将是一个完全相同但完全“其他”的接口,即使它具有完全相同的成员签名

我认为大会1和2可以合并为一个。确保接口声明和类定义都是公共的。键不是两次导入COM接口,而是一次导入并引用它

编辑:反映到评论:

不要将COM接口和类与.NET接口混淆。(顺便说一句,注释提到的是类id而不是接口id,这在COM中是两个不同的东西。)

通过互操作层高度支持访问.NET中的COM类和接口。互操作层为您完成所有转换和编组,您可以通过方便的.NET接口访问COM组件。然而,这个接口是在(互操作)组件中定义的,这些组件(对于众所周知的、经常使用的COM组件)是分布式的,或者是原始COM组件下载的一部分。因此,从字面上说,他们是在每台机器上,他们需要

还有一个概念上的差异,即在COM中,客户端(引用组件)仅通过guid(这是类id)引用服务器(引用组件),然后请求接口的多态实现,也仅通过guid。因此,客户机可以通过只知道两个GUI并执行1-2 COM OS调用来使用组件的特定接口。这是互操作层中的黑框。在.NET中,客户端和服务器之间的绑定要强大得多

如果要定义此类接口,则必须执行相同的操作:以某种方式在一个程序集中定义接口,然后将其分发给其他程序集使用接口并引用此接口的每台计算机

如果您不接受最佳实践,请选择:

  • 您可以使用反射来实现类似的松散绑定,但在本例中,这被认为是黑客行为,似乎没有必要。请准备好,方法名和类名将是字符串,或者至少键入不正确不会导致编译错误,但会导致运行时错误

  • 您也可以在.NET中定义和实现COM组件,但我认为这不是目标。COM是一种传统的(很酷的)技术,在当时是非常进步的(不被理解/批评),但这是四分之一个多世纪前(当它被引入时)

    • (这是问题作者的答案)

      在DLL中: 使组件
      COM可见=选中

      using System;
      using System.Runtime.InteropServices;
      
      namespace ComExport
      {
          [ComImport]
          [Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
          [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
          [TypeIdentifier()]
          public interface ComClass1Interface
          {
              string DoCall();
          }
      
          [Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938")]
          [ClassInterface(ClassInterfaceType.AutoDual)]
          public class ComClass1 : ComClass1Interface
          {
              public string DoCall()
              {
                  return "internal function called";
              }
              public override string ToString()
              {
                  return "comclass1.tostring";
              }
          }
      }
      
      然后在EXE中

      using System;
      using System.Runtime.InteropServices;
      using System.Windows.Forms;
      
      namespace ComExportTester
      {
          public partial class Form1 : Form
          {
              public Form1()
              {
                  InitializeComponent();
      
                  this.Load += (o1, e) => Close();
      
                  Type t;
                  object o;
                  ComExport.ComClass1Interface i1;
                  string s = "";
                  try
                  {
                      t = Type.GetTypeFromCLSID(new Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"));
                      s += "Type found \t: " + (t == null ? "no" : "yes") + "\n";
                      o = t == null ? null : Activator.CreateInstance(t);
                      s += "object created \t: " + (o == null ? "no" : o.ToString()) + "\n";
                      i1 = o as ComExport.ComClass1Interface;
                      s += "interface cast \t: " + (i1 == null ? "no" : "yes") + "\n";
                      if (i1 != null)
                          s += i1.DoCall() + "\n";
                  }
                  catch (Exception x)
                  {
                      s += x.Message + "\n";
                  }
                  MessageBox.Show(s);
              }
          }
      }
      namespace ComExport
      {
          [ComImport]
          [Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
          [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
          [TypeIdentifier()]
          public interface ComClass1Interface
          {
              string DoCall();
          }
      }
      
      在这两方面:


      设置x86或x64(在“任意CPU”模式下编译和运行会引发“未注册”异常!)

      为什么不引用公共程序集?为什么不将接口拉入其自己的程序集,并让它们都引用该程序集?“我需要在多个程序集中声明相同的接口,但不引用公共库”. 这是不可能的。除非它们都引用一个定义,否则接口就不一样了。C#不支持duck类型。很难猜到为什么程序员坚持这样做。从技术上讲,COM接口从.NET 4.0开始仅通过其[Guid]支持类型等效。用于实现互操作程序集的“嵌入互操作类型”属性的功能。Google“.net类型等效”了解更多信息。这是一个使用COM的DirectShow项目。我无法与其他供应商共享通用代码,但我制作的对象已成功加载到GraphiEdit中,并可用于我机器上的所有其他视频处理系统。如果我使用类id“70E102B0-5556-11CE-97C0-00AA0055595A”,我会得到一个内置的视频渲染器,然而,它以某种方式成功地公开了IBaseFilter接口。由于这个特殊的例子是DirectShow,我的程序正在访问系统级已知接口,因此通用全局级接口被隐藏在操作系统中。我的库中的一个类实现了该接口,但由于某些原因,我无法从单独的程序集访问它。我的两个程序集都可以访问实现该接口的系统上的所有其他程序集,系统上的所有程序集都可以访问我的类-只是我的两个类不能相互访问。@g.pickardou,实际上,你可以,但它是一个。请