Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

177
Vistas
¿Hay alguna manera más fácil de registrar dependencias cuando quiero que solo una de ellas sea "especial"?

En C#, por supuesto, se pueden registrar muchas dependencias para DI con una línea corta a través de Microsoft.Extensions.DependencyInjection, especialmente cuando hay exactamente una implementación para una interfaz. Por ejemplo, supongamos que Service1 depende de otros tres servicios, y uno de ellos de dos más:

 _serviceCollection.AddTransient<IService1,Service1>(); _serviceCollection.AddTransient<IOtherService,OtherService>(); _serviceCollection.AddTransient<IAnotherOne,Service1>(); _serviceCollection.AddTransient<IService4,Service4>(); _serviceCollection.AddTransient<IService5,Service5>(); _serviceCollection.AddTransient<IService6WithAReallyLongName,Service6WithAReallyLongName>();

¿Hay una forma más breve/más fácil de registrar dependencias cuando quiero que solo una (o algunas) de ellas sean "especiales" , tal vez especificadas con un método de fábrica? Una variación del ejemplo aquí es la siguiente; Quiero especificar un tipo concreto especial para una dependencia de un servicio y probablemente tenga sus propias dependencias. En el código llamado desde Startup.cs, creo que me veo obligado a especificar todas las dependencias, y todas las dependencias son mi dependencia especial:

 _serviceCollection.AddTransient<IService1>(x => new Service1( x.GetRequiredService<IOtherService>(), x.GetRequiredService<IAnotherOne>(), new SpecialService4( x.GetRequiredService<IService5>(), x.GetRequiredService<IService6WithAReallyLongName>() ) ));

(Por supuesto, también podría ser AddSingleton o AddScoped).

Tenga en cuenta lo anterior, solo quiero que SpecialService sea la dependencia concreta especial que estoy registrando; los otros cinco pueden tomar la implementación predeterminada registrada en el ejemplo de código superior.

Esa es realmente una gran cantidad de ingreso de código quisquilloso y propenso a errores, y cada vez que se lo explico a uno de mis compañeros de equipo, se lamentan y lloran con razón. Solo quiero anular una cosa, ¿por qué tengo que anular seis cosas para hacerlo?

Estoy buscando algo como la siguiente sintaxis hipotética:

 _serviceCollection.AddTransient<IService1, Service1>() .WithParameter<IService4, SpecialService4>();

Y luego haga que los constructores completen automáticamente los concretos para IOtherService , IAnotherOne , IService5 e IService6WithAReallyLongName automáticamente.

¿Hay alguna manera mejor, aparte de ir a Autofac o alguna otra biblioteca de contenedores DI, para especificar una dependencia concreta especial para un parámetro sin especificar todos los demás parámetros de dependencias Y todos los parámetros no especiales de la dependencia concreta especial? ¿Quizás hay un paquete NuGet que agrega algo de azúcar sintáctico para registrar dependencias con AddTransient/AddScoped/AddSingleton?

Parece que esto sucedería todo el tiempo una vez que tengamos más de una clase concreta para una interfaz, por lo que me sorprende que esta necesidad no sea más frecuente.

over 4 years ago · Santiago Trujillo
4 Respuestas
Responde la pregunta

0

Puede usar interfaces de marcador donde SpecialService1 tiene una dependencia en IDependency1 pero implementado de una manera "especial" por SpecialDependency1 :

 interface IDependency1 { /* Something useful here */ } interface ISpecialDependency1 : IDependency1 { /* Nothing here - just a marker */ } class SpecialService1 : IService1 { readonly IDependency1 dependency1; public SpecialService1(ISpecialDependency1 dependency1) => this.dependency1 = dependency1; } class SpecialDependency1 : ISpecialDependency1 { /* So very special */ }

Debe agregar los siguientes servicios al contenedor:

 services .AddTransient<IService1, SpecialService1>() .AddTransient<ISpecialDependency1, SpecialDependency1>();

Esto no se parece en nada a lo que ha descrito como su solución propuesta, pero creo que resuelve su problema. Personalmente, y sin conocer su caso de uso, probablemente estaría en el campo de "lamento y llanto" si tuviera que trabajar con algo como esto.

over 4 years ago · Santiago Trujillo Denunciar

0

Una forma de limpiar un poco su código DI es registrar la clase especial como sí misma (o con una interfaz de marcador si insiste en registrar solo interfaces). Luego registre su delegado de fábrica para el consumidor, pero use el contenedor DI para construir la clase especial. Al igual que:

 _serviceCollection.AddTransient<SpecialService4>(); _serviceCollection.AddTransient<IService1>(x => new Service1( x.GetRequiredService<IOtherService>(), x.GetRequiredService<IAnotherOne>(), x.GetRequiredService<SpecialService4>()));

Editar

Esto me ha estado molestando y finalmente me di cuenta de por qué. Originalmente vi esta técnica en el contexto de registrar decoradores. El método ActivatorUtilities.CreateInstance se puede usar para simplificar esto así:

 _serviceCollection.AddTransient<SpecialService4>(); _serviceCollection.AddTransient<IService1>(provider => ActivatorUtilities.CreateInstance<Service1>( provider, provider.GetRequiredService<SpecialService4>()));

La idea básica detrás de ActivatorUtilities.CreateInstance es que puede proporcionar implementaciones de algunos o todos los parámetros del constructor, y todo lo que no se proporcione se recuperará del proveedor de servicios.

Editar 2

Dado que esto es algo que ocasionalmente he considerado usar yo mismo, creé un paquete que es básicamente una fachada sobre ActivatorUtilities.CreateInstance :

https://www.nuget.org/packages/ServiceProviderContextualBinding/

Ejemplo de uso:

 _serviceCollection.AddTransient<SpecialService4>(); _serviceCollection.WithReplacement<IService4, SpecialService4>() .AddSingleton<IService1, Service1>();

Hay otro paquete que hace algo similar, pero también incluye escaneo de ensamblaje:

https://www.nuget.org/packages/ForEvolve.DependencyInjection.ContextualBindings/

over 4 years ago · Santiago Trujillo Denunciar

0

Puede hacer algo similar usando registros con clave. Desafortunadamente, la compilación en el contenedor DI no proporciona dicha función, pero puede usar un contenedor IoC de terceros para reemplazar una compilación en uno. Por ejemplo , Autofac tiene registro/resolución de servicio con clave.

over 4 years ago · Santiago Trujillo Denunciar

0

Lo que está solicitando se llama Contextual Binding , y es una característica que algunos marcos de Inyección de Dependencia más avanzados han puesto a disposición, a costa del rendimiento y la simplicidad. Microsoft.Extensions.DependencyInjection no admite el enlace contextual.

Puede encontrar algunos ejemplos de soluciones alternativas en las respuestas a esta pregunta similar .

Una estrategia que al menos puede simplificar un poco su enfoque actual es crear un registro para el tipo concreto y aprovecharlo para evitar vincular estrechamente su fábrica de servicios con las dependencias de ese tipo:

 _serviceCollection.AddTransient<SpecialService4>(); _serviceCollection.AddTransient<IService1>(x => new Service1( x.GetRequiredService<IOtherService>(), x.GetRequiredService<IAnotherOne>(), x.GetRequiredService<SpecialService4>() ));
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda