Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot register a struct instance with autofac

I just started moving to Autofac from Unity and I have a problem when trying to register an instance.

public static void Register(ContainerBuilder containerBuilder,
                            CancellationToken shutDownCancellationToken)
{
    containerBuilder.RegisterType<CancellationToken>();
    containerBuilder.RegisterInstance(shutDownCancellationToken);
}

I get the following error:

The type 'CancellationToken' must be a reference type in order to use it as parameter 'T' in the generic type or method 'RegistrationExtensions.RegisterInstance<T>(ContainerBuilder, T)'

Anyone knows how to register an already created struct instance?

like image 813
pantonis Avatar asked Dec 19 '22 08:12

pantonis


1 Answers

The RegisterInstance method as a class constraint that disallow struct registration but CancellationToken is a struct this is why you have this error message. To bypass this constraint, you can register your instance using the Register method.

builder.Register(_ => source.Token).As<CancellationToken>(); 

As long as your struct is immutable, you will have the expected behavior, but if you use a mutable struct, the instance won't be share. In your case, CancellationToken is immutable you won't have any weird side effect.


But why has RegisterInstance a class constraint ?

When you register an instance using the RegisterInstance method, the expected behavior is to share the same instance each time the object is injected.

By definition a struct acts like a copy and not like a reference. See Struct vs Class for more information.

Imagine you have the following struct and service using this struct :

public struct Foo
{
    public Int32 A { get; set; }
}
public class Service
{
    public Service(Foo foo)
    {
        this._foo = foo;
    }

    private Foo _foo;

    public void Set(Int32 a)
    {
        this._foo.A = a;
    }

    public void Print()
    {
        Console.WriteLine(this._foo.A);
    }
}

and the following code using these service :

var builder = new ContainerBuilder();

Foo f = new Foo();
builder.Register(_ => f).As<Foo>();
builder.RegisterType<Service>();
IContainer container = builder.Build();

Service service1 = container.Resolve<Service>();
Service service2 = container.Resolve<Service>();

service1.Set(3);
service1.Print();
service2.Print();

Even if you register only one instance of Foo it will display 3 and 0. I think this is the reason why RegisterInstance has a class constraint.

like image 183
Cyril Durand Avatar answered Dec 24 '22 02:12

Cyril Durand