且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

是否确定(AB)使用CoCl​​assAttribute提供接口的默认实现?

更新时间:2022-10-14 20:25:36

你不应该这样做的关键原因是,你开始COM生命周期管理上,这并不需要一个对象的实例。 .NET现在必须做一些COM互操作,其中包括一个安全堆栈散步,公寓线程检查和的AddRef /释放的东西。

相反,我会考虑寻找依赖注入(控制模式反转)和通用Service Locator模式。我想重点了解构造函数注入,因为它是preferred模式的依赖管理。

这是我做我的图书馆。比方说,我想写一个日志服务(人为的例子)。我想有两个核心组件:

MyStuff.Logging.Contracts - 这里就是我会宣布ILogger接口 MyStuff.Logging - 这里就是我会写不同的日志实现我可能有这样FileLogger,DatabaseLogger等

然后在我的应用程序,我会使用任何Ninject或Unity(DI容器),以ILogger的默认实现关联。

I recently discovered that it's possible to "new up" an interface in C# by decorating the interface with the CoClassAttribute to specify a default implementation.

[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();

I'm aware that this feature exists primarily to support COM-interop, but I was wondering if this would be a reasonable way to associate interfaces with default implementations in generic class-libraries.

I have two questions:

  1. Are there any gotchas with doing this? I'm not an expert on COM-interop and I don't know if this will have any negative impact on POCOs. I haven't run any major tests, but the the IL for my example seems ok (a normal newobj instruction on FooImpl rather than calls to Type.GetTypeFromCLSID and Activator.CreateInstance).

  2. Even if this would work smoothly, are there other reasons (say from an API-design perspective) to avoid this?

The key reason you shouldn't do this is that you are starting the COM lifecycle management on an instance of an object that doesn't need it. .NET will now have to do some COM interop that includes a security stack walk, apartment threading checks, and addref/release stuff.

Instead, I would consider looking at dependency injection (inversion of control pattern) and the Common Service Locator Pattern. I would focus on understanding constructor injection as it is the preferred pattern for dependency management.

Here's what I do in my libraries. Let's say I want to write a logging service (contrived example). I would have two core components:

MyStuff.Logging.Contracts - Here is where I would declare the ILogger interface MyStuff.Logging - Here is where I would write the different logging implementations I might have like FileLogger, DatabaseLogger, etc.

Then in my application I would use either Ninject or Unity (DI containers) to associate ILogger with the default implementation.