Можно ли (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-взаимодействия, но мне было интересно, если это будет разумным способом связать интерфейсы с реализациями по умолчанию в общих библиотеках классов.
У меня есть два вопроса:
Есть ли какие-нибудь ошибки с этим? Я не эксперт по COM-взаимодействию, и я не знаю, окажет ли это какое-либо негативное влияние на POCO. Я не проводил каких-либо серьезных тестов, но IL для моего примера кажется нормальным (нормальный
newobj
инструкция поFooImpl
а не призывы кType.GetTypeFromCLSID
а такжеActivator.CreateInstance
).Даже если это будет работать гладко, есть ли другие причины (скажем, с точки зрения разработки 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 предназначен для документации.
Конечно, некоторые устаревшие инструменты будут иметь проблемы с чтением ваших /// комментариев, но они также не смогут прочитать ваши атрибуты.