-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Interface instantiation and Interface ctors #13792
Comments
Sounds like you want to both mix concerns of the programming language with a dependency injection container and you want to invert the inversion of control turning dependency injection into a service locator. Effectively this is a Cartesian product of anti-patterns. |
For one there is nothing wrong with service locators/object resolvers. And this could just be an extension of the type resolver event that already exists on the assemble. The nice thing about this is it would centralize dependency injection to one location versus each platforms and assembly using their own pattern. This would also be better replacing all of the "new MyObject" all over your code with "new MyInterface". In your tests (the reason people care about DI/IOC) could easily have a have a method to setup the mock dependencies in the same way. More important would be the interface constructors. |
If this was combined with the request to add interfaces to anonymous types most mocking frameworks could go away. |
I wholeheartedly disagree. While dependency injection still has a service locator at its root it should be exceptionally rare for any consuming code to actually treat it as such beyond what is necessary to furnish inversion of control within a given framework. Outside of that it's just a bad idea. Beyond that, this proposal is asking the language and BCL to both take a dependency on the concept of dependency injection. This is also asking the language to build in a concept already perfectly handled through libraries. There is little difference/benefit between the two: var myObject2 = new IMyInterface(new Type1(), new Type2());
//
var myObject2 = locator.GetService<IMyInterface>(new Type1(), new Type2()); The request to have anonymous types that can implement interfaces would be a dupe of #13, which unfortunately the team has already weighed in on and rejected: #13 (comment) |
The only gain I see here is the type-safely of the constructor parameters which should be done via factory pattern anyways. |
The damage caused by IoC container preaching will take years to overcome. http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern |
I'm with @HaloFour here in strongly disagreeing with you. There is lots wrong with service locators, to the extent that it can be argued that they are an anti-pattern. @dsaf's first link is to an article by Mark Seemann that explains this well, so I won't go back over the reasons here.
Dependency injection is already baked into the C# language. Any language that supports interfaces and functions being passed as parameters into other functions provides all the tooling needed to implement Pure DI (see the second link in @dsaf's comment). Whilst IoC can be used to simplify DI, using one before having a proper understanding of DI is akin to giving an F1 car to someone who can't drive. It's powerful, but unless you know what you are doing with it, it results in a mess. The most common mistake made by those using IoC is to inject the container, rather than the dependency, thus creating an injected service locator, rather than a global one. You proposal unfortunately goes further: it's not even injecting anything anywhere; it's actually a proposal for a baked-in service locator. No thanks; C# has enough anti-patterns built into it from the early days, without adding more.
You shouldn't have
People use DI as it removes coupling and so makes the code more maintainable. Easier-to-write, less brittle, tests assist in making code more maintainable, but they are not the raison d'être for DI. Mocking frameworks exist, not because the language doesn't support them directly, but because people write code that needs mocking. Again, there are plenty of articles that explain why needing to use a mocking framework is a bad thing, such as this one by Sebastien Lambla. The need for mocking frameworks should be avoided by writing code that doesn't need mocking, rather than building one into the framework.
As @alrz has pointed out, the factory pattern already exists for handling this. And of course, that factory should be injected (via |
Anti-patterns, anti-patterns everywhere... get a grip and learn to program. Software development is not a religion and there is more than one way to do a thing. Injection though constructors is just one way to do DI and it creates its own complexities and messes in software architecture. |
As a note, most so far ignored the interface abstract constructor. That is the more useful thing that I would like to see. And if Roslyn was the pipeline that was originally proposed adding the interface instantiation would be easy without requiring massive IOC containers, service locators or, factories. |
Acknowledging bad practices is learning to program. The language should not encourage nor lead developers into doing the wrong thing.
Constructors are neither virtual nor inherited. Defining them on an interface makes as much sense as defining an abstract construct on an abstract class: it doesn't. The creation of an object is not a part of its contract. |
It would be nice to provide an example of such problems. |
everytime you want to reference a new object from within your object you have to add a property, modify the constructor and update your DI registration. versus just saying |
@mwwhited Yes you do, and there's a reason for that. It allows the resolution of the object to fail immediately rather than later at some arbitrary time and in some intermediate state. The dependencies required to use that object should all be known and ready prior to being able to use the object. |
And that's where code contracts and static analysis come in but those are off topic here. |
Neither code contracts nor static analysis help. Code contracts can't know of dependency trees or how they're intended to resolve anymore than arbitrary interfaces do (or should). At best you can try to enforce the contract at the point of trying to use the service locator, but that leaves you with the exact same pit of failure that service locator leaves you with already. As for static analysis, the entire point of either service locator or dependency injection is separation of concerns. The compiler can't (and shouldn't be able to) determine if you've completely configured those dependencies as necessary in order to use them. You can feel free to use service locator. The pattern and factory methods to do so are relatively simple. Don't pollute the language with something that is so easily managed by a library and is frankly an awful way to do things. |
CC can do that with invariants and pre-conditions. But again off topic. I should have switched the order on my suggestions. The one that I see as being more useful is the interface constructor definitions. (I'd really like to see abstract static methods on interfaces also but based on how .Net works that is unlikely to happen.) |
CC would still be doing that later than it should be, which is before the object is created. Constructors can't be virtual any more than static methods can. The CLR doesn't allow it. |
How is compile time after the object is created? |
Static analysis and code contracts merely attempt to patch a weak type system.
I think any benefits of this would be covered by #2206 Also see Skeet's analysis: https://codeblog.jonskeet.uk/2008/08/29/lessons-learned-from-protocol-buffers-part-4-static-interfaces |
Not remotely possible, the entire point of service locator being that the consumer of the contract is decoupled from the implementation of the contract. If you can configure/replace the implementations based on configuration (why on Earth would you be using service locator or dependency injection otherwise) then it's impossible for the compiler to ensure that those registrations will exist or be correct. |
with pre and post conditions you can have the compiler ensure that something required is provided and something is returned as required. I already use code contracts in this pattern and it works fantastic so I'm not sure why you say it's not possible. the constructor wouldn't need to be virtual. It could even be sealed abstract just as a place holder/hint to the compiler. (and I know CIL would flip out on this as is but that could be fixed as well.) Being that it is on the interface there is no code to execute. Heck, how about just extending the |
And I agree with John Skeet that it would be interesting and yes these may require changes to the runtime as well but all of that is possible. Even limit on a programming language/platform was added by someone. They can be changed or removed by someone just the same. |
The compiler can't ensure anything, it can only emit the code that may ensure it at run time. It still fails at run time after the dependency has been created (and may have already done arbitrary things). Combining service locator with CC in order to guarantee dependencies is, if anything, more verbose and a horrifically inefficient way of hacking inversion of control. I can't see how that could possibly be preferable to simply declaring dependencies as constructor arguments (my preference) and having the container resolve them.
Constructors would need to be virtual in order for abstract constructors to work. The CLR would still need a vtable slot to fill in order to dispatch the call.
That is proposal #2206. |
Language design has moved to https://github.com/dotnet/csharplang . Closing as the conversation appears to be stale. |
Feature Request: Interface instantiation and Interface ctors
In this new dependency injection world it would be really nice to be able to instantiate an interface. The idea would the
new IMyInterface
would be replaced with either a standard service locator or a type resolve event that could be handled by your favorite IOC container.It would be even more amazing to have abstract constructors for interfaces as this would be great with generics.
The text was updated successfully, but these errors were encountered: