Skip to content
An embeddable IoC container in a single C# file, with support for extensibility and conventions
C#
Branch: master
Clone or download
Latest commit 6e5f8d8 Jan 7, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
Pocket.Container.CumulativeRegistration xml fix Oct 31, 2017
Pocket.Container.For.Microsoft.Extensions.DependencyInjection update nuspecs Nov 28, 2017
Pocket.Container.Tests fix resolution for structs with default values Jul 10, 2018
Pocket.Container fix resolution for structs with default values Jul 10, 2018
Pocket.TypeDiscovery.Tests
.gitignore update nuspecs for correct behavior under .NET Core Aug 16, 2017
LICENSE initial checkin Dec 11, 2014
PocketContainer.sln remove differentiation of net45 from netstandard versions of TypeDisc… Dec 15, 2017
README.md Update README.md Jan 7, 2019
appveyor.yml another appveyor.yml fix Oct 31, 2017

README.md

PocketContainer

Join the chat at https://gitter.im/jonsequitur/PocketContainer

Build Status NuGet Status

An embeddable IoC container in a single C# file, with support for extensibility and conventions.

When you install the PocketContainer NuGet package, it will add the PocketContainer C# file to your project. PocketContainer is an internal class and it's quite small, around 250 lines of code including the comments. Embedding it as a class (versus having an assembly) accomplishes a few goals:

  • Discourages usage as a service locator.
  • If you want the capabilities of an IoC container within a library, it avoids forcing an additional assembly dependency on consumers of that library.
  • Enables customizations that are very specific to your use case because you can tinker with the code or compose behaviors using partial classes.

How do you use it?

PocketContainer has familiar-looking Register and Resolve methods, with generic and non-generic variants:

    var container = new PocketContainer();

    container.Register<IDoThings>(c => c.Resolve<DoSpecificThings>());
    
    // or...
    
    container.Register(typeof(IDoThings), c => c.Resolve<DoSpecificThings>());

The Register methods all take delegates. Many of the constructs that most containers have for lifetime can be replicated using closures.

The Resolve methods will try to recursively satisfy all arguments to the longest constructor on a type. Concrete types don't require explicit registration. This is the default strategy for PocketContainer, but others can be added. This extensibility mechanism allows you to specify how to handle unregistered types the first time someone tries to resolve them.

Here's an example that resolves a concrete type when only one is found for a given interface or abstract class:

    container.AddStrategy(type =>
    {
        if (type.IsInterface || type.IsAbstract)
        {
            var implementations = Discover.ConcreteTypes()
                                          .DerivedFrom(type)
                                          .ToArray();

            if (implementations.Count() == 1)
            {
                return c => c.Resolve(implementations.Single());
            }
        }
        return null;
    });

If a strategy returns a delegate, PocketContainer registers it and uses it to resolve further calls for that type. If a strategy returns null, PocketContainer moves on to the next strategy. If no strategy is found that can resolve the type, an exception is thrown.

Extensibility via partial classes

The Clone extension is an example of a partial class being used to extend PocketContainer. Because this extensibility mechanism relies on access to PocketContainer's private fields, these fields are considered to be part of the backwards compatibility contract of PocketContainer, and a change to one of them constitutes a breaking change and will incur a major version bump.

Lazy and Func

PocketContainer can return Lazy<T> and Func<T> instances that, when resolved or invoked, result in Resolve calls into the container. Lazy<T> and Func<T> do not need to be explicitly registered, but this behavior can be overridden by registering them.

Support for other similar types can be added trivially using AddStrategy.

You can’t perform that action at this time.