Можно ли (ab) использовать CoClassAttribute, чтобы обеспечить реализацию по умолчанию для интерфейса?

Недавно я обнаружил, что можно "обновить" интерфейс в C#, украсив интерфейс CoClassAttribute указать реализацию по умолчанию.

[ComImport, Guid("579A4F68-4E51-479A-A7AA-A4DDC4031F3F"), CoClass(typeof(FooImpl))]
public interface IFoo
{
    void Bar();
}

public class FooImpl : IFoo
{
    public void Bar() { }
}

...

// Constructs a FooImpl
IFoo foo = new IFoo();

Я знаю, что эта функция существует главным образом для поддержки COM-взаимодействия, но мне было интересно, если это будет разумным способом связать интерфейсы с реализациями по умолчанию в общих библиотеках классов.

У меня есть два вопроса:

  1. Есть ли какие-нибудь ошибки с этим? Я не эксперт по COM-взаимодействию, и я не знаю, окажет ли это какое-либо негативное влияние на POCO. Я не проводил каких-либо серьезных тестов, но IL для моего примера кажется нормальным (нормальный newobj инструкция по FooImpl а не призывы к Type.GetTypeFromCLSID а также Activator.CreateInstance).

  2. Даже если это будет работать гладко, есть ли другие причины (скажем, с точки зрения разработки API), чтобы этого избежать?

2 ответа

Основная причина, по которой вам не следует этого делать, заключается в том, что вы запускаете управление жизненным циклом COM для экземпляра объекта, который ему не нужен. Теперь.NET нужно будет выполнить некоторое COM-взаимодействие, которое включает в себя обход стека безопасности, проверки потоков в квартирах и утилиты addref/release.

Вместо этого я хотел бы рассмотреть вопрос о внедрении зависимостей (инверсия шаблона управления) и шаблон общего локатора обслуживания. Я хотел бы сосредоточиться на понимании внедрения конструктора, так как это предпочтительный шаблон для управления зависимостями.

Вот что я делаю в своих библиотеках. Допустим, я хочу написать сервис логирования (надуманный пример). Я хотел бы иметь два основных компонента:

MyStuff.Logging.Contracts - здесь я бы объявил интерфейс ILogger. MyStuff.Logging - здесь я бы написал различные реализации журналирования, которые у меня могут быть, например FileLogger, DatabaseLogger и т. Д.

Затем в моем приложении я бы использовал Ninject или Unity (контейнеры DI), чтобы связать ILogger с реализацией по умолчанию.

Используйте комментарии intelisense:

    /// <summary>
    /// Explain here all about interface
    /// </summary>

вместо того, чтобы взламывать атрибуты, так как это может иметь неприятные последствия в чьей-либо реализации с полуотражением, которая использует ваш класс. Атрибуты используются инструментами, которые используют рефлексию, intelisense предназначен для документации.

Конечно, некоторые устаревшие инструменты будут иметь проблемы с чтением ваших /// комментариев, но они также не смогут прочитать ваши атрибуты.

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