0

我需要编写一个免费注册的 COM 互操作库,请参阅 MSDN 链接

要求之一是,我引用

“要使基于 .NET 的类与来自 COM 的无注册表激活兼容,该类必须具有默认构造函数并且必须是公共的。”

当我阅读它时,我需要创建以下内容......(这在技术上有效,我通过 COM 实例化它没有问题)

[ComVisible(true)]
[Guid("...")]
public interface ITest
{
    X();
    Y();
}

[ComVisible(true)]
[Guid("...")]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class Test : ITest
{
    private string x;

    public Test() // default constructor
    {
    }

    X()
    {
        // do something with "x" BUT "x" MUST be initialized before this method is called
    }

    Y()
    {
        // do something else with "x" BUT "x" MUST be initialized before this method is called
    }
}

我正在寻找确保在调用任何方法之前(通过接口)初始化此类的最佳方法,因此,除了构造函数之外,我初始化“x”的下一个最佳选择是什么?据我所知,用参数重载构造函数不是一个选项 - 通常我会使用带参数的构造函数初始化这个类,但是使用无注册 COM,我没有那个选项(或者我没有? )。

我认为我的替代方案是“初始化”功能,例如...

public interface ITest
{
    Initialize(string x);
    X();
    Y();
}

public class Test : ITest
{
    private string x;
    private bool Initialized;

    public Test() // default constructor
    {
        Initialized = false;
    }

    Initialize(string x)
    {
        this.x = x;
        Initialized = true;
    }

    X()
    {
        if (Initialized)
        {
            // do something with x
        }
        else
        {
            throw...
        }
    }

    Y()
    {
        if (Initialized)
        {
            // do something else with x
        }
        else
        {
            throw...
        }
    }
}

我觉得这很混乱,但可行......但我错过了什么更好的选择?

4

2 回答 2

2

You are not missing that much. COM uses a universal object factory and, because it is universal, it can't take any arguments. Which is why you must create a C# class with a default constructor, there isn't any way to pass constructor arguments.

The solution is a pretty simple one, all that you need is your own object factory and expose it to the client code. The factory function can take any arguments you need to create your C# object. And you make your Test class inaccessible to the client code, since you want to insist it uses the factory, simply done by omitting the [ComVisible] attribute. Some sample declarations that fleshes this out:

[ComVisible(true)]
public interface ITestFactory {
    ITest Create(string arg);
}

[ComVisible(true)]
public class TestFactory {
    public ITest Create(string arg) {
        return new Test(arg);
    }
}

[ComVisible(true)]
public interface ITest {
     // etc...
}

internal class Test {
    private string needed;
    public Test(string arg) {
        needed = arg;
    }
    // ITest methods ...
}

Good examples of these kind of object factories can be found in Office interop. Excel does not allow you to create a spreadsheet directly for example, you have to use Application.Workbooks.Add().

于 2017-11-04T10:44:41.787 回答
1

Lazy<T> 是您的朋友,与您的 Initialize() 想法相同,但语法更简洁且线程安全。

于 2017-11-04T07:17:26.900 回答