Rub*_*uck 3 c# com properties readonly
我有一个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";
}
}
Run Code Online (Sandbox Code Playgroud)
通常,我会将该财产声明为:
public string Message { get; private set; }
Run Code Online (Sandbox Code Playgroud)
但这显然不起作用,因为COM不能使用接受参数的构造函数.
所以,问题是:
如何确保只使用一次private set或不使用readonly?
根据代码项目的这篇文章:
如果方法调用失败或业务逻辑验证失败,则.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;
}
}
Run Code Online (Sandbox Code Playgroud)
从以下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
Run Code Online (Sandbox Code Playgroud)
导致错误的结果.

设置后,有效地使属性为只读属性.
但这会导致客户端遇到运行时错误.这里的解决方案是创建一个类工厂,如@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";
}
}
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个具有默认构造函数的类工厂,并接受与构造函数相同的参数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);
}
}
Run Code Online (Sandbox Code Playgroud)
所以,现在如果客户端试图设置Message属性可言,它得到一个编译时错误信息.
