Um den Prinzipien von OOP und SOLID zu folgen , werden hÀufig AbhÀngigkeitsinjektionsbibliotheken verwendet. Es gibt viele dieser Bibliotheken, und alle sind durch eine Reihe gemeinsamer Funktionen verbunden:
API zum Definieren des AbhÀngigkeitsgraphen
Zusammensetzung von Objekten
Objektlebenszyklusmanagement
Ich war daran interessiert zu verstehen, wie es funktioniert, und der beste Weg, dies zu tun, besteht darin, eine eigene IoC.Container- AbhÀngigkeitsinjektionsbibliothek zu schreiben . Es ermöglicht Ihnen, komplexe Dinge auf einfache Weise zu erledigen: Es funktioniert gut mit generischen Typen - andere nicht , es ermöglicht Ihnen, Code ohne InfrastrukturabhÀngigkeiten zu erstellen und bietet eine gute Leistung im Vergleich zu anderen Àhnlichen Lösungen, jedoch NICHT im Vergleich zu einem reinen DI-Ansatz.
Mit klassischen AbhĂ€ngigkeitsinjektionsbibliotheken können wir das AbhĂ€ngigkeitsdiagramm einfach definieren und verlieren an Leistung. Dies zwingt uns, Kompromisse zu suchen. Wenn Sie also mit einer groĂen Anzahl von Objekten arbeiten mĂŒssen, kann die Verwendung der AbhĂ€ngigkeitsinjektionsbibliothek die AusfĂŒhrung der Anwendung verlangsamen. Einer der Kompromisse besteht darin, die Verwendung von Bibliotheken in diesem Teil des Codes zu vermeiden und Objekte auf altmodische Weise zu erstellen. Dadurch wird das vordefinierte und vorhersagbare Diagramm beendet, und jeder dieser SonderfĂ€lle erhöht die GesamtkomplexitĂ€t des Codes. ZusĂ€tzlich zu den Auswirkungen auf die Leistung können klassische Bibliotheken aufgrund von Fehlkonfigurationen zu Laufzeitproblemen fĂŒhren.
In reinem DI erfolgt die Objektzusammensetzung manuell: Normalerweise gibt es viele Konstruktoren, die andere Konstruktoren als Argumente verwenden, und so weiter. Es fallen keine zusĂ€tzlichen Gemeinkosten an. Der Compiler ĂŒberprĂŒft die Richtigkeit der Komposition. Das Verwalten der Lebensdauer von Objekten oder anderer Probleme wird behandelt, wenn sie auf eine Weise auftreten, die fĂŒr eine bestimmte Situation effektiv ist oder vom Autor des Codes bevorzugt wird. Mit zunehmender Anzahl neuer Klassen oder mit jeder neuen AbhĂ€ngigkeit wĂ€chst die KomplexitĂ€t des Objektzusammensetzungscodes immer schneller. Irgendwann können Sie die Kontrolle ĂŒber diese KomplexitĂ€t verlieren, was die weitere Entwicklung erheblich verlangsamt und zu Fehlern fĂŒhrt. Daher ist meiner Erfahrung nach reines DI anwendbar, solange die Codemenge klein ist.
Was ist, wenn wir nur die besten dieser AnsÀtze beibehalten:
API
DI
""
, . , - . .NET , /API . , JIT.
, - Pure.DI! - , . NuGet beta , :
Pure.DI.Contracts , .NET Framework 3.5, .NET Standard .NET Core , , .NET 5 6, .NET Framework 2, . API, , , C#. API IoC.Container.
.NET 5 source code generator Roslyn Pure.DI. IDE , . ââ . , .
, , ââ ââ:
interface IBox<out T> { T Content { get; } }
interface ICat { State State { get; } }
enum State { Alive, Dead }
â â :
class CardboardBox<T> : IBox<T>
{
public CardboardBox(T content) => Content = content;
public T Content { get; }
}
class ShroedingersCat : ICat
{
//
private readonly Lazy<State> _superposition;
public ShroedingersCat(Lazy<State> superposition) =>
_superposition = superposition;
//
//
public State State => _superposition.Value;
public override string ToString() => $"{State} cat";
}
, . DI, SOLID.
, , . Pure.DI.Contracts Pure.DI. ââ :
static partial class Glue
{
// ,
// ,
private static readonly Random Indeterminacy = new();
static Glue()
{
DI.Setup()
//
.Bind<State>().To(_ => (State)Indeterminacy.Next(2))
//
.Bind<ICat>().To<ShroedingersCat>()
//
.Bind<IBox<TT>>().To<CardboardBox<TT>>()
//
//
.Bind<Program>().As(Singleton).To<Program>();
}
}
Setup()
DI ââ. static partial , , âDIâ. Setup()
string . âIndeterminacyâ, Glue static partial, .
Setup()
Bind<>()
To<>()
, :
.Bind().To()
ICat - , , .NET . ShroedingersCat - , .NET . , , . - , . , Bind<>()
, To<>()
. :
Bind<>()
,
As(Lifetime)
, ,
Tag(object)
, , ,
, :
Transient - ,
Singleton - ,
PerThread -
PerResolve -
Binding - ILifetime
, , . , :
.Bind().Tag(âFatâ).Tag(âFluffyâ).To()
, Bind<>()
To<>()
- . , . , , typeof(IBox<>)
API , âTTâ. - IBox<TT>
, CardboardBox<TT>
. ? , . TT, TT1, TT2 .. API . . c , [GenericTypeArgument]
, :
[GenericTypeArgument]
public class TTMy: IMyInterface { }
To<>()
. . , â â . [Obsolete]
. , , , - . To<>(factory)
. , ,
.Bind<IBox>().To<CardboardBox>()
.Bind<IBox>().To(ctx => new CardboardBox(ctx.Resolve()))
To<>(factory)
lambda , . lambda , - ctx, . ctx.Resolve()
TT . Resolve()
, - object.
!
class Program
{
//
public static void Main() => Glue.Resolve<Program>().Run();
private readonly IBox<ICat> _box;
internal Program(IBox<ICat> box) => _box = box;
private void Run() => Console.WriteLine(_box);
}
void Main()
Glue.Resolve<Program>()
. Composition Root, , , , , . Resolve<>()
:
static class ProgramSingleton
{
static readonly Program Shared =
new Program(
new CardboardBox<ICat>(
new ShroedingersCat(
new Lazy<State>(
new Func<State>(
(State)Indeterminacy.Next(2))))));
}
, Program Singleton Resolve<>()
Program . , Shared
ProgramSingleton, Glue.
, . ,
ShroedingersCat(Lazy<State> superposition)
Lazy<>
.NET. , Lazy<>
? , Pure.DI BCL Lazy<>, Task<>, Tuple<..>
, . , . DependsOn()
, , .
, ? - Func<>
, BCL . , ICat
, - Func<ICat>
, .
. , . , IEnumerable<ICat>,
ICat[]
.NET, IReadOnlyCollection<T>
. , IEnumerable<ICat>
.
, , API . To<>(factory)
c lambda , , .
, , - . API . , , , TagAttribute:
:
.Bind<ICat>().Tag(âFatâ).Tag(âFluffyâ).To<FatCat>()
:
BigBox([Tag(âFatâ)] T content) { }
TagAttribute :
TypeAttribute - , , , ,
OrderAttribute - , /
OrderAttribute -
, , Pure.DI.Contracts. , , , . , :
TypeAttribute<>()
TagAttribute<>()
OrderAttribute<>()
, - : , , . 0, , . , , , âInjectAttributeâ, , .
. , Roslyn API, IDE , . . , IDE , , . . , , , . , fallback : IFallback
. Resolve<>()
Wird aufgerufen, wenn eine AbhĂ€ngigkeit nicht gefunden werden kann und: das erstellte Objekt zur Injektion zurĂŒckgibt, eine Ausnahme auslöst oder null zurĂŒckgibt , um das Standardverhalten zu belassen. Wenn die Fallback- Strategie angehĂ€ngt ist, Ă€ndert der Generator den Fehler in eine Warnung, vorausgesetzt, die Situation liegt unter Ihrer Kontrolle und der Code wird kompilierbar.
Hoffe, diese Bibliothek ist hilfreich. Alle Kommentare und Ideen werden sehr geschÀtzt.