Right now, interfaces are tied to an assembly. If you want to implement an interface, you have to reference the assembly that the interface is declared in. For instance, let’s say I’m writing a framework, aptly named ZeeFramework (what it actually does and the implementation both don’t matter), and in this framework I have an interface for a logger:
public interface IZeeLogger
void DoZeeLogging(); //Ironically sounds like "Doozie Logging"
Now, in your application you’re writing, you want to use this amazing ZeeFramework (it’s been called framework of a generation, so obviously it’s amazing). And with this logging component, you want to use log4net. You have 2 options:
- You write an implementation yourself
- You contact the creators of log4net and tell them to write an implementation
The first one sucks because each and every person who wants to use ZeeFramework has to write their own implementation. The second one sucks because the creators of log4net have to create and maintain a package with an implementation for this logger. And other logging frameworks, like nlog, have to do the same.
Okay. Let’s say you convince log4net and nlog to write implementations for everyone to use. Great. Now they both have binary dependencies on ZeeFramework just so they can implement
IZeeLogger. And what if you, because you’re mean and don’t like ZeeFramework, create a framework named WhyFramework with another logging interface:
public interface IWhyLogger
And we run into the same issue – either everyone writing an application has to write their own implementation, or the logging frameworks have to each maintain a package with an implementation. The logging interfaces are essentially the same – why do we need all of these implementations?
Let’s all live in harmony
In a perfect world, we’d have one logging abstraction –
ILogger – that every framework would use. My ZeeFramework and your WhyFramework would be dependent on that, and log4net and nlog and whatever other loggers there are would each maintain a single implementation of that single interface.
So how would that work? We could have a package whose sole member would be the the
ILogger interface, but then we’re back to having seemingly unnecessary binary dependencies. And besides, who would maintain that? Who would own it?
The AssemblyNeutral attribute
That’s where the
[AssemblyNeutral] attribute comes in. When an interface is decorated with this attribute, it’s identity is no longer tied to an assembly. Interfaces are now just contracts, and the code basically says “hell, all I need to be able to do is call
Log – can you log or not?”. We’re getting down to Duck Typing – if it walks like a duck, and talks like a duck, well then it must be a duck which means it can do duck-like things.
This removes the unnecessary binary dependencies that we have today, and allows for more loose coupling, which as developers we strive for.
To do this, anyone who wants to use the assembly neutral interface must define it in their code (it must be exactly the same!). For instance, if I defined this in ZeeFramework and log4net defined it in their package, we’d be good to go:
public interface ILogger
void Log(string message);
The goal is to:
- Allows for loose coupling
- Less code duplication
- Less dependency hell
- More community defined standards
The ASP.NET vNext team wants to create a vibrant open source eco-system. Part of that includes allowing the community to decide on standards and contracts. This allows the community to more easily achieve that. The more easily these standards can be adopted the more likely they will be adopted.