Is order of dependencies guaranteed when injecting IEnumerable<T>

 ̄綄美尐妖づ 提交于 2019-12-01 03:08:08
Nicholas Blumhardt

No, there's no ordering guaranteed here. We've considered extensions to enable it but for now it's something to handle manually.

Just as extra help for people like me landing on this page... Here is an example how one could do it.

public static class AutofacExtensions
  {
    private const string OrderString = "WithOrderTag";
    private static int OrderCounter;

    public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle>
      WithOrder<TLimit, TActivatorData, TRegistrationStyle>(
      this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder)
    {
      return registrationBuilder.WithMetadata(OrderString, Interlocked.Increment(ref OrderCounter));
    }

    public static IEnumerable<TComponent> ResolveOrdered<TComponent>(this IComponentContext context)
    {
      return from m in context.Resolve<IEnumerable<Meta<TComponent>>>()
             orderby m.Metadata[OrderString]
             select m.Value;
    }
  }

I don't mean to self-promote, but I have also created a package to solve this problem because I had a similar need: https://github.com/mthamil/Autofac.Extras.Ordering

It uses the IOrderedEnumerable<T> interface to declare the need for ordering.

I know this is an old post but to maintain the order of registration, can't we just use PreserveExistingDefaults() during registration?

builder.RegisterInstance(serviceInstance1).As<IService>().PreserveExistingDefaults();    
builder.RegisterInstance(serviceInstance2).As<IService>().PreserveExistingDefaults();

// services should be in the same order of registration
var services = builder.Resolve<IEnumberable<IService>>();

I didn't find any fresh information on topic and wrote a test which is as simple as (you'd better write your own):

var cb = new ContainerBuilder();
cb.RegisterType<MyClass1>().As<IInterface>();
// ...
using (var c = cb.Build())
{
    using (var l = c.BeginLifetimeScope())
    {
        var e = l.Resolve<IEnumerable<IInterface>>().ToArray();
        var c = l.Resolve<IReadOnlyCollection<IInterface>>();
        var l = l.Resolve<IReadOnlyList<IInterface>>();
        // check here, ordering is ok
    }
}

Ordering was kept for all cases I've come up with. I know it is not reliable, but I think that in the current version of Autofac (4.6.0) ordering is wisely kept.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!