Create components

All about creating and preparing components for later use.


Go back

Component information

Fun facts about Snow components.

Components are the main building block in Snow. They can require and be injected into other components.

Generally speaking, any class that will make use of Snow, be it to request a dependency, to be injected as a dependency itself, or both must be tagged as a component. As an exception, the main class (which extends ISnowRunnable) can request dependencies without being a component (though it can be marked as such).

Components are defined by the use of the [Component] attribute, or other attribute that extends it. Snow provides the [Service] attribute as an example of this behavior. The difference between these attributes is only for added clarity to the users.

Make a component from scratch

Let's add some functionality to the project.

Create a new class in your project. For organization purposes, we advise to put all component classes inside a folder, and name them with a Component or Service suffix. Of course, you can follow a different method.

Then, mark the class with the [Component] or [Service] attribute:

[Service]
internal class NumbersService
{
}

Snow components don't have to be public classes. They can be internal or even private. The same applies to their methods, though you won't be able to call private methods unless you use reflection.

As components will be injected already instanced, static methods are unnecessary:

[Service]
internal class NumbersService
{
    internal int Sum(int a, int b)
    {
        return a + b;
    ]
}

This class is now a valid component, and other components will be able to call the Sum() method. However, some components could require some initialization logic.

For this, you have two solutions: Either add a default constructor, or a static factory method marked with the [CreateInstance] attribute. Note that these two alternatives should not be combined.

[Service]
internal class NumbersService
{
    private int _factor;
    
    // Alternative 1: Default constructor
    public NumbersService()
    {
        _factor = 2;
    }
    
    // Alternative 2: Static factory method
    [CreateInstance]
    internal static NumbersService Initialize()
    {
        return new NumbersService
        {
            _factor = 2;
        }
    }
    
    internal int Multiply(int num)
    {
        return num * _factor;
    }
}

It's possible for a component to have other components inside. It doesn't need any special work, simply request any needed dependencies as indicated in the 'Inject Components' tutorial.

Components implementing interfaces

Some remarks on components extending interfaces.

In the IOC world, it's very common to inject components as an interface instead of as a concrete type, for easier replacement of implementations.

Snow allows this in the form of 'Type Aliases', with the following limitations:

  • An interface should only have one component implementation. For example, INumbersService should only be implemented by the NumbersServiceFoo class. It's possible to have other implementing classes, as long as they are not components.
  • However, a component can extend and be aliased by multiple interfaces. For example, NumbersServiceFoo can extend INumbersService and IMultiplicationService.
  • All type aliases must be valid superinterfaces. That is, NumbersServiceFoo cannot be aliased by IEnumerable<TeddyBear> unless it correctly implements such interface.

To indicate that a component has a type alias, use the [TypeAlias] attribute on it:

internal interface INumbersService
{
    int Sum(int a, int b);
}

[Service]
[TypeAlias(typeof(INumbersService)]
internal class NumbersService : INumbersService
{
    public int Sum(int a, int b)
    {
        return a + b;
    }
}

You're all done!

Your project now has some components that will soon be injected as dependencies.


Go back