【问题标题】:My C# COM Library Isn't Working Right; Can't Instantiate The Class and a Method Appears As a Property我的 C# COM 库工作不正常;无法实例化类并且方法显示为属性
【发布时间】:2011-08-10 13:51:12
【问题描述】:

我正在用 C# 编写一个 COM DLL 来处理 X.12 格式文档的导入和导出,因此我可以在 Access 数据库和自定义程序中使用它来处理我公司的 EDI。我有一个要编译的 DLL,但结果令人失望,我想知道我是否遗漏了什么; COM“从头开始”对我来说是一个新领域(我之前为 Excel 制作了一个功能区,但所有这些都由一个向导处理)。

我已经阅读了this article on MSDN 并遇到了this question here 来让我的 DLL 和 TLB 编译和注册。这是我的 X12Segment 类的骨架和 COM 可见性的接口:

using System;
using System.Collections;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace X12
{
    [Guid("28A76274-05EE-45B2-A8EF-ADD5A5B351DE"),
    ComVisible(true)]
    public interface IX12Segment
    {
        [DispId(1)]
        string SegmentType { get; set; }
        [DispId(2)]
        string[] Fields { get; set; }
        [DispId(3)]
        char FieldDelimiter { get; set; }
        [DispId(4)]
        char SegmentDelimiter { get; set; }
        [DispId(5)]
        string ToString(char sep, char eol);
        [DispId(6)]
        string ToString();
        [DispId(7)]
        Type GetFieldEnum();
    }

    [Guid("B321599A-E5EC-4510-A021-E9A8B4D6293E"),
    ClassInterface(ClassInterfaceType.None),
    ComVisible(true)]
    public class X12Segment : IX12Segment
    {
        private string _type;

        protected ArrayList _fields;
        protected short _minFields = -1;
        protected short _maxFields = -1;
        protected short[][] _fieldSizes = { new short[] { -1, -1 } };
        protected char _sep;
        protected char _eol;

        public enum Field { }

        /// <summary>
        /// Creates a new X.12 segment of the supplied type,
        /// optionally with a supplied number of fields or
        /// values.
        /// </summary>
        /// <param name="segType">The type of segment (eg "ISA", "GS")</param>
        /// <param name="fields">Each string is a field
        /// within the segment</param>
        public X12Segment(string segType, params string[] fields)
            : this(segType)
        {
            //Do cool stuff
        }

        /// <summary>
        /// Creates a new X.12 segment from a string.
        /// </summary>
        /// <param name="segType">The type of segment (eg "ISA", "GS")</param>
        /// <param name="segment">The string to parse</param>
        public X12Segment(string segType, string segment)
            : this(segType)
        {
            //Do cool stuff
        }

        /// <summary>
        /// Creates a new X.12 segment of the supplied type,
        /// optionally with a supplied number of fields or
        /// values.
        /// </summary>
        /// <param name="segType">The type of segment (eg "ISA", "GS")</param>
        /// <param name="fieldCount">The number of fields
        /// in this segment</param>
        public X12Segment(string segType, int fieldCount) : this(segType)
        {
            //Do cool stuff
        }

        /// <summary>
        /// Creates a new X.12 segment of the supplied type,
        /// optionally with a supplied number of fields or
        /// values.
        /// </summary>
        /// <param name="segType">The type of segment (eg "ISA", "GS")</param>
        public X12Segment(string segType) : this()
        {
            //Do cool stuff
        }

        public X12Segment()
        {
            //Do cool stuff
        }

        /// <summary>
        /// Gets or sets the segment type.
        /// </summary>
        public string SegmentType
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets all of the fields in the segment,
        /// in the form of an array of strings.
        /// </summary>
        public string[] Fields
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the character used to seperate fields in the segment.
        /// </summary>
        public char FieldDelimiter
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the character denoting the end of the segment.
        /// </summary>
        public char SegmentDelimiter
        {
            get;
            set;
        }

        /// <summary>
        /// Generates an X.12 formatted segment.
        /// </summary>
        /// <param name="sep">The field delimiter to use.</param>
        /// <param name="eol">The segment delimiter to use.</param>
        /// <returns>An X.12 formatted string.</returns>
        public string ToString(char sep, char eol)
        {
            //Do cool stuff
        }

        /// <summary>
        /// Generates an X.12 formatted segment.
        /// </summary>
        /// <returns>An X.12 formatted string.</returns>
        public override string ToString()
        {
            //Do cool stuff
        }

        /// <summary>
        /// Returns the Type associated with the Field enumeration of this object.
        /// </summary>
        /// <returns>A System.Type of this object's Field enumeration.</returns>
        public virtual Type GetFieldEnum()
        {
            //Do cool stuff
        }
    }
}

现在,当我打开 VBA 并添加引用时,该类会显示在 IntelliSense 中。但是,当我 Dim 使用 X12Segment 类型的变量,然后放入点运算符时,弹出的 IntelliSense 窗口显示 ToString() 是一个属性,而不是一个方法。此外,ToString 的重载显示为 ToString_2。当我尝试Set seg = New X12Segment 时,VBA 告诉我这是对 New 关键字的无效使用。

我在这里错过了什么?

更新

我已根据下面的 cmets 和答案修改了我的代码,并且我有解决 New 不工作和我的 ToString 重载在 IntelliSense 中看起来很时髦的解决方案。但是,出现了一个新问题;尝试访问字段给我错误。 seg.Fields = someStringArray 收到一条错误消息,提示“函数或接口标记为受限,或者函数使用 Visual Basic 不支持的自动化类型”。

【问题讨论】:

  • 我不明白你的问题。这些 ARE 属性,即使在您的 C# 代码中也是如此。
  • 哇。出于某种原因,我认为我拥有的不止这些。但无论哪种方式,ToString 都是一种方法,它显示为一个属性。而且我无法在 VBA 中实例化我的 X12Segment。
  • 方法重载在 COM 中无效(以及其他一些技术 - 请参阅 WCF、Web 服务)。这就是为什么您的 ToString() / ToString_2() 会这样显示的原因 - 编译器保护您免受该实现细节的影响...

标签: c# vba com


【解决方案1】:

[ComVisible] 类必须具有无参数构造函数。 COM 没有将参数传递给构造函数的机制。您只提供了带参数的构造函数,这就是 VBA 不允许您使用 New 关键字的原因。

COM 也不支持方法重载。您需要为方法提供不同的名称。如果您不这样做,那么类型库导出器将自动处理它。因此 ToString_2()。

【讨论】:

  • 那里有一个 noarg ctor,结果发现 VBA 非常挑剔,希望我把命名空间和类放在一起;刚刚从this post on xtremevbtalk 中发现了这一点。感谢您和 GalacticCowboy 解释过载不起作用!我仍然不明白为什么 ToString() 被显示为属性,即使在删除重载之后也是如此。
  • 嗯,调用不带参数的函数和使用属性 getter 的 VBA 语法是相同的。所以它可能看起来像一个属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-16
  • 2017-09-29
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多