Регистрация Бесплатная COM Interop Initialization - конструктор без параметров

Мне нужно написать бесплатную библиотеку COM Interop для регистрации, см. Ссылку 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"? Насколько я могу сказать, перегрузка конструктора с параметром не является опцией - Обычно я инициализирую этот класс конструктором, который принимает параметры, однако в случае регистрации Free COM у меня нет этой опции (или нет?).

Я думаю, что моей альтернативой является функция "Initialize", например...

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...
        }
    }
}

Я чувствую, что это грязно, но выполнимо... но какой лучший вариант мне не хватает?

2 ответа

Решение

Вы не так сильно скучаете. COM использует универсальную фабрику объектов и, поскольку она универсальна, она не может принимать никаких аргументов. Вот почему вы должны создать класс C# с конструктором по умолчанию, нет способа передать аргументы конструктора.

Решение довольно простое, все, что вам нужно, это ваша собственная фабрика объектов и предоставить ее клиентскому коду. Функция factory может принимать любые аргументы, необходимые для создания вашего объекта C#. И вы делаете ваш класс Test недоступным для клиентского кода, поскольку вы хотите настаивать на том, чтобы он использовал фабрику, просто сделав это, пропустив атрибут [ComVisible]. Некоторые примеры объявлений, которые конкретизируют это:

[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 ...
}

Хорошие примеры такого рода объектных фабрик можно найти в Office Interop. Excel не позволяет вам создавать электронную таблицу напрямую, например, вы должны использовать Application.Workbooks.Add().

Lazy - ваш друг, та же идея, что и у Initialize(), но более чистый синтаксис и потокобезопасность.

Другие вопросы по тегам