我有一个C#类,我想通过COM向VB6公开。问题是这需要为类提供默认构造函数。因此,我必须将setter暴露给客户端,以便可以将这些属性设置为开头。
例如:
[Guid("B1E17DF6-9578-4D24-B578-9C70979E2F05")]
public interface _Class1
{
[DispId(2)]
string Message { get; set; }
[DispId(1)]
string TestingAMethod();
}
[Guid("197A7A57-E59F-41C9-82C8-A2F051ABA53C")]
[ProgId("Project.Class1")]
[ClassInterface(ClassInterfaceType.None)]
public class Class1 : _Class1
{
public string Message { get; set; }
public Class1() { } //default constructor for COM
public Class1(string message)
{
this.Message = message;
}
public string TestingAMethod()
{
return "Hello World";
}
}
通常,我会将该属性声明为:
public string Message { get; private set; }
但这显然不会起作用,因为COM无法使用接受参数的构造函数。
所以,问题是:
如何在不使用private set
或readonly
的情况下确保仅设置属性一次?
答案 0 :(得分:7)
根据this article on Code Project:
如果方法调用失败或业务逻辑验证失败,则.NET组件会引发异常。 此异常 通常有一个失败的HRESULT分配给它和一个错误描述 与之相关联。 CCW收集了错误代码等详细信息, 来自.NET异常的错误消息等,并提供这些详细信息 以COM客户端可以使用的形式。
强调我的。
那么,我们可以检查是否已设置私有字段。如果是的话,抛出异常。
private string message;
public string Message {
get { return message; }
set
{
if (message != null)
{
throw new ReadOnlyPropertyException("Class1.Message can not be changed once it is set.");
}
message = value;
}
}
从以下VB6 / VBA代码
中使用它Dim cls As New Rubberduck_SourceControl.Class1
cls.Message = "Hello"
Debug.Print cls.Message
cls.Message = "Goodbye" 'we expect a read only error here
Debug.Print cls.Message
导致错误。
有效地将属性设置为只读属性。
但这会导致客户端遇到运行时错误。这里的解决方案是创建一个类@Hans Passant建议的工厂。
理解COM理念很重要。 COM提供了一个类工厂来创建对象,但它不支持传递任意参数。这就是为什么你总是需要一个默认的构造函数。好吧,没问题,只需创建自己的工厂。隐藏Class1并编写Class1Factory类。使用返回_Class1的CreateClass1()方法。它可以采取你需要的任何参数。
所以,我按照原来的方式实现了这个类。 (没有默认构造函数和private set
属性。请注意,该接口只有get
属性。
[Guid("B1E17DF6-9578-4D24-B578-9C70979E2F05")]
public interface _Class1
{
[DispId(2)]
string Message { get; }
[DispId(1)]
string TestingAMethod();
}
[Guid("197A7A57-E59F-41C9-82C8-A2F051ABA53C")]
[ProgId("Project.Class1")]
[ClassInterface(ClassInterfaceType.None)]
public class Class1 : _Class1
{
public string Message { get; private set; }
public Class1(string message)
{
this.Message = message;
}
public string TestingAMethod()
{
return "Hello World";
}
}
然后我创建了一个类工厂, 有一个默认构造函数,并且接受与Class1
的构造函数相同的参数。
[Guid("98F2287A-1DA3-4CC2-B808-19C0BE976C08")]
public interface _ClassFactory
{
Class1 CreateClass1(string message);
}
[Guid("C7546E1F-E1DB-423B-894C-CB19607972F5")]
[ProgId("Project.ClassFactory")]
[ClassInterface(ClassInterfaceType.None)]
public class ClassFactory : _ClassFactory
{
public Class1 CreateClass1(string message)
{
return new Class1(message);
}
}
因此,现在,如果客户端尝试设置Message
属性,,则会出现 编译时 错误
答案 1 :(得分:1)
它不漂亮,并没有暴露出它只读"这样的事实,但它会像私人跟踪bool那样工作吗?
[Guid("197A7A57-E59F-41C9-82C8-A2F051ABA53C")]
[ProgId("Project.Class1")]
[ClassInterface(ClassInterfaceType.None)]
public class Class1 : _Class1
{
private bool _isMessageSet = false;
private string _message;
public string Message
{
get { return _message; }
set
{
if (!_isMessageSet)
{
_message = value;
_isMessageSet = true;
}
}
}
public Class1() { } //default constructor for COM
public Class1(string message)
{
this.Message = message;
}
}