Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
DI under the hood. This is what DI containers automate for you
using System;
using System.Threading;
namespace PureDI
{
class Program
{
static void Main(string[] args)
{
// Create the singletons once
var singletons = new SingletonDependencies();
// Create a transient object
var myClass = new MyTransientClass1(singletons.Singleton1, singletons.Singleton2, new MyTransientClass2(new MyTransientClass3()));
// Create another transient object
var otherClass = new MyTransientClass2(new MyTransientClass3());
}
static void WebRequest(SingletonDependencies singletons)
{
// Make a per request scope with access to the singletons
var requestScope = new ScopedDependencies(singletons);
// Create a controller passing the request scoped dependency and transient dependency
var controller = new MyController(requestScope.Scoped1);
}
}
public class MyController
{
public IScoped1 Scoped1 { get; }
public MyController(IScoped1 scoped1)
{
Scoped1 = scoped1;
}
}
// Transient dependencies
public interface IMyTransientClass1 { }
public interface IMyTransientClass2 { }
public interface IMyTransientClass3 { }
public class MyTransientClass1 : IMyTransientClass1
{
public ISingleton1 Singleton1 { get; }
public ISingleton2 Singleton2 { get; }
public IMyTransientClass2 MyTransientClass2 { get; }
public MyTransientClass1(ISingleton1 singleton1, ISingleton2 singleton2, IMyTransientClass2 myOtherClass)
{
Singleton1 = singleton1;
Singleton2 = singleton2;
MyTransientClass2 = myOtherClass;
}
}
public class MyTransientClass2 : IMyTransientClass2
{
public IMyTransientClass3 MyTransientClass3 { get; }
public MyTransientClass2(IMyTransientClass3 anotherClass)
{
MyTransientClass3 = anotherClass;
}
}
public class MyTransientClass3 : IMyTransientClass3
{
}
// Scoped dependencies
public interface IScoped1 { }
public interface IScoped2 { }
public interface IScoped3 { }
public class Scoped1 : IScoped1
{
}
public class Scoped2 : IScoped2
{
public IScoped1 Scoped1 { get; }
public Scoped2(IScoped1 scoped1)
{
Scoped1 = scoped1;
}
}
public class Scoped3 : IScoped3
{
public IMyTransientClass1 MyTransientClass1 { get; }
public IScoped2 Scoped2 { get; }
public Scoped3(IMyTransientClass1 myTransientClass1, IScoped2 scoped2)
{
MyTransientClass1 = myTransientClass1;
Scoped2 = scoped2;
}
}
// The class that represents all scoped dependencies
public class ScopedDependencies
{
private IScoped1 _scoped1;
private IScoped2 _scoped2;
private IScoped3 _scoped3;
private object _lockObject = new object();
private readonly SingletonDependencies _singletons;
public ScopedDependencies(SingletonDependencies singletons)
{
_singletons = singletons;
}
public IScoped1 Scoped1 => LazyInitializer.EnsureInitialized(ref _scoped1, ref _lockObject, () => new Scoped1());
public IScoped2 Scoped2 => LazyInitializer.EnsureInitialized(ref _scoped2, ref _lockObject, () => new Scoped2(Scoped1));
public IScoped3 Scoped3 => LazyInitializer.EnsureInitialized(ref _scoped3, ref _lockObject, () => new Scoped3(
new MyTransientClass1(
_singletons.Singleton1,
_singletons.Singleton2,
new MyTransientClass2(new MyTransientClass3())),
Scoped2));
}
// Singleton dependencies
public interface ISingleton1 { }
public interface ISingleton2 { }
public class Singleton1 : ISingleton1
{
public ISingleton2 Singleton2 { get; }
public Singleton1(ISingleton2 singleton2)
{
Singleton2 = singleton2;
}
}
public class Singleton2 : ISingleton2 { }
// The class that represents all singleton dependencies
public class SingletonDependencies
{
private ISingleton1 _singleton1;
private ISingleton2 _singleton2;
private object _lockObject = new object();
public ISingleton1 Singleton1 => LazyInitializer.EnsureInitialized(ref _singleton1, ref _lockObject, () => new Singleton1(Singleton2));
public ISingleton2 Singleton2 => LazyInitializer.EnsureInitialized(ref _singleton2, ref _lockObject, () => new Singleton2());
}
}
@desjoerd

This comment has been minimized.

Copy link

@desjoerd desjoerd commented Jan 20, 2020

You are missing the dispose on the scoped dependencies :)

@davidfowl

This comment has been minimized.

Copy link
Owner Author

@davidfowl davidfowl commented Jan 20, 2020

You are missing the dispose on the scoped dependencies :)

On purpose, because it gets complicated (its not just scoped, it's also transient disposable objects).

@desjoerd

This comment has been minimized.

Copy link

@desjoerd desjoerd commented Jan 20, 2020

Thanks, did not know that, but sounds logical. Wonder if this also happens with singletons, because if they use the resolver to resolve idisposable transient dependencies that could result in memory leaks.

@davidfowl

This comment has been minimized.

Copy link
Owner Author

@davidfowl davidfowl commented Jan 21, 2020

Thanks, did not know that, but sounds logical. Wonder if this also happens with singletons, because if they use the resolver to resolve idisposable transient dependencies that could result in memory leaks.

https://github.com/dotnet/extensions/issues/2207

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.