gpt4 book ai didi

C# COM 实现可枚举而不引用 MSCORLIB

转载 作者:太空狗 更新时间:2023-10-30 01:30:45 37 4
gpt4 key购买 nike

我正在创建一个 COM 接口(interface),它应该允许在 Visual Basic 脚本中使用 For Each 和在 C++ 中使用 IEnumVariant。问题是我不希望 C++ 客户端应用程序需要导入 mscorlib.tlb。

到目前为止我的界面是:

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ICars : System.Runtime.InteropServices.ComTypes.IEnumVARIANT
{
int Count { get; }
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Cars : ICars
{
int ICars.Count => throw new NotImplementedException();

int IEnumVARIANT.Next(int celt, object[] rgVar, IntPtr pceltFetched)
{
throw new NotImplementedException();
}

int IEnumVARIANT.Skip(int celt)
{
throw new NotImplementedException();
}

int IEnumVARIANT.Reset()
{
throw new NotImplementedException();
}

IEnumVARIANT IEnumVARIANT.Clone()
{
throw new NotImplementedException();
}
}

TlbExp 吐出这段代码:

// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: carsIEnumerator.tlb

[
uuid(3BBCEAA2-9498-48BF-8053-1CEFB3C1C86F),
version(1.0),
custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "ClassLibraryIEnumerator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

]
library ClassLibraryIEnumerator
{
// TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");

// Forward declare all types defined in this typelib
interface ICars;

[
odl,
uuid(ABD2A9E4-D5C5-3ED9-88AF-4C310BD5792D),
version(1.0),
dual,
oleautomation,
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ClassLibraryIEnumerator.ICars")

]
interface ICars : IDispatch {
[id(0x60020000), propget]
HRESULT Count([out, retval] long* pRetVal);
};

我怎样才能避免这种情况?

即使我只有自定义界面和单个类(不使用任何 .NET 类型),引用仍然存在。

最佳答案

IEnumVARIANT 类型声明必须来自某处。它不是每个编译器都知道的标准类型,如 int。如果您自己编写 IDL,则可以使用 #import "oaidl.idl" 来包含定义。但这在 .NET 中行不通,因为类型库导出器不使用 IDL。所以它来自导出商确实知道的地方,mscorlib.tlb

解决方法是将接口(interface)声明放在您自己的代码中,而不是使用 mscorlib 中的接口(interface)声明。从 Reference Source 复制/粘贴它或者这个:

[Guid("00020404-0000-0000-C000-000000000046")]   
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface IEnumVARIANT
{
[PreserveSig]
int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0), Out] object[] rgVar, IntPtr pceltFetched);

[PreserveSig]
int Skip(int celt);

[PreserveSig]
int Reset();

IEnumVARIANT Clone();
}

并在您的 ICars 声明中使用 YourNamespace.IEnumVARIANT。


声明您自己的枚举器接口(interface)类型也是一种解决方案,IEnumVARIANT 不会赢得任何奖励。你可以放弃没有人使用的靠不住的方法,你可以让它成为类型安全的。如果您也控制客户端代码,或者不必在脚本语言中保持 foreach 是一个可接受的替代方案。考虑:

[ComVisible(true)]
public interface ICarEnumerator {
ICar Next();
}

以及 ICars 接口(interface)中的 ICarEnumerator GetCars()


最后但同样重要的是,考虑完全不实现迭代器。在客户端代码中让它看起来像一个数组:

[ComVisible(true)]
public interface ICars
{
int Count { get; }
ICar this[int index] { get; }
}

关于C# COM 实现可枚举而不引用 MSCORLIB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43408872/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com