Discussion: Functionality Injection #1292
Replies: 13 comments
-
What makes this convoluted and confusing system better than dependency injection? |
Beta Was this translation helpful? Give feedback.
-
@amirebrahimi Scala has features that support this. Both implicit parameters and instantiation time specified mixins can be used for this. I think implicit parameters are more aligned with your scenario. @svick as you say, you could do this with dependency injection but it would be very cumbersome because you would need to inject a bunch of optional delegates and so would need to have all these extra constructors. Extension methods allow you to decouple entirely external operations while keeping them organized around the types they apply to and keeping the syntax uniform. |
Beta Was this translation helpful? Give feedback.
-
That's not what I meant. You would inject just the E.g.: public interface IGetRayVisibility
{
bool IsRayVisible(Transform rayOrigin);
bool IsConeVisible(Transform rayOrigin);
}
class DelegateGetRayVisibility : IGetRayVisibility
{
private readonly Func<Transform, bool> isRayVisible;
private readonly Func<Transform, bool> isConeVisible;
public DelegateGetRayVisibility(
Func<Transform, bool> isRayVisible, Func<Transform, bool> isConeVisible)
{
this.isRayVisible = isRayVisible;
this.isConeVisible = isConeVisible;
}
public bool IsRayVisible(Transform rayOrigin) => isRayVisible(rayOrigin);
public bool IsConeVisible(Transform rayOrigin) => isConeVisible(rayOrigin);
} |
Beta Was this translation helpful? Give feedback.
-
@svick thank you for clarifying, I was indeed imagining something different. |
Beta Was this translation helpful? Give feedback.
-
@svick - What is instantiating DelegateGetRayVisibility and how would a developer make use of this in one of their own classes? |
Beta Was this translation helpful? Give feedback.
-
@amirebrahimi Most likely a Dependency Injection container (e.g. Castle Windsor or ASP.NET Core's Microsoft.Extensions.DependencyInjection). Though I must admit I don't know if the DI containers that are commonly used in .Net support injecting delegates well. Though my main objection to your design is that implementing an interface to request a service is logically completely wrong. When you implement an interface, you tell the outside about what your type can do, implemented interfaces are not there for implementation details. And when you need a service from the outside, that service should be represented by a separate object (or at least a separate |
Beta Was this translation helpful? Give feedback.
-
@svick - I'm familiar with DI, but at the time of designing this system I didn't like the registration, resolution, or use of factories. Although there is no longer coupling among concrete types, I find that most projects have simply replaced those interconnected dependencies with interfaces. There is also a dependency on the DI system itself. I realize interfaces weren't meant for how we've used them. One of the benefits is that we can look at what services are requested via interfaces on a class as opposed to properties or fields that would be on the class that make use of an interface. I don't like the idea of a class requesting services via a factory or having to create/modify a custom constructor with each new service added. For further discussion purposes, let's say we replace
|
Beta Was this translation helpful? Give feedback.
-
This is dependency injection: public DelegateGetRayVisibility(
Func<Transform, bool> isRayVisible, Func<Transform, bool> isConeVisible)
{
this.isRayVisible = isRayVisible;
this.isConeVisible = isConeVisible;
} We have injected the dependencies ( To that extent, I really dislike the idea of adding any sort of DI "system" to the language. There are plenty of good IoC containers out there that can do the hard work if it's needed, and there's always plain and simple, pure DI to fall back on if it's not needed. |
Beta Was this translation helpful? Give feedback.
-
Thank you for the link about Pure DI. I am probably disliking IoC containers that I've seen and what I'm doing is DI-ish anyway. The code block you're referring to was suggested by @svick and is not my original code, but I understand that it is DI. I wasn't seeing |
Beta Was this translation helpful? Give feedback.
-
Dependency injection with delegates isn't much different from dependency injection with interfaces. And if classes are written correctly they should have no dependency whatsoever on the container. I just wrote a blog post on this with examples using a few different containers. |
Beta Was this translation helpful? Give feedback.
-
Castle Windsor does and I sometimes make heavy use of this. Pure DI would be a massive ton of boilerplate in some projects, but if I had an analyzer to generate and update the root composition code... 🤔 |
Beta Was this translation helpful? Give feedback.
-
Thanks for the post @scotthannen One thing I'm still not fond of is having to use custom constructors to inject additional functionality. Currently, with what I described in the original post, it isn't necessary to create objects with a custom constructor and functionality can be connected, disconnected, or replaced temporarily at any point. All that is necessary for determining whether to connect additional functionality is to check whether an object has implemented a functionality request (interface). @jnm2 - not sure I followed your last comment - we're you referring to something that could determine via reflection what dependencies were required for an object (by looking at its constructor) and have instantiation handled dynamically? |
Beta Was this translation helpful? Give feedback.
-
@amirebrahimi No, I meant something that generates the code statically that e.g. Castle Windsor already generates at runtime, and inserts it into my program. Less dynamic, not more. The resulting code would be pure DI. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
The work on default interface methods or the mixins proposal might solve the need I'm about to express, but it may also require other functionality to be added to the language.
I've been using the term "functionality injection", but these are essentially delegates combined with extension methods.
In EditorVR (a toolkit for authoring VR content inside of VR for Unity, we wanted developers to be able to extend our system simply by requesting functionality that they need and nothing more. We make use of interfaces in order to declare on a class that this functionality is needed. No singletons are accessed directly and the actual implementations are hidden and can be replaced with other implementations if need be (e.g. different implementation for builds vs. in our authoring environment).
I'll copy an example of a functionality interface here for convenience:
A class that makes use of this functionality would have:
The implementation of this functionality by the system is installed as such:
Originally, these extension methods were not extension methods at all and were simply delegates that an interface required to be added to the class. Then, our system would install the correct delegate when an object was instantiated with a reference to this interface. We found it cumbersome to require a developer to create a property for this in their class. and eventually moved to using extension methods with static delegates. Unfortunately, we lost the feature of being able to define a custom delegate just for specific objects when we moved over to extension methods.
There are a few features desired:
Thoughts? Is this actually called something else? Is this possible?
Beta Was this translation helpful? Give feedback.
All reactions