3

Is it possible to register same interface twice, where the first resolves to a default implementation and the second has a name and resolves to another type.

Example:

container.RegisterType(typeof(IMyInterface), typeof(MyDefaultImplementation));
container.RegisterType(typeof(IMyInterface), typeof(MySecondImplementation),"Second Implementations name");

So,

Resolve<IMyInterface>("non existing name")

Should resolve MyDefaultImplementation.

Th3B0Y
  • 884
  • 1
  • 12
  • 30
  • Yes, you can create your custom `BuilderStrategy`. You can take a look at the accepted answer on this question. But you may want to reconsider if it's actually what you want to do... http://stackoverflow.com/questions/1380375/custom-object-factory-extension-for-unity – smoksnes Jul 20 '16 at 11:38

2 Answers2

5

If you're OK with using the container you can do an extension method:

public static class UnityExtensions
{
    public static T TryResolve<T>(this IUnityContainer container, string name)
    {
        if (container.IsRegistered<T>(name))
            return container.Resolve<T>(name);

        return container.Resolve<T>();
    }
}

And use it like:

container.RegisterType<IMyInterface, Foo>();
container.RegisterType<IMyInterface, Bar>("bar");

var foo = container.TryResolve<IMyInterface>("non-existing");
// foo will be Foo
var bar = container.TryResolve<IMyInterface>("bar");
// bar will be Bar.

public interface IMyInterface { }
public class Foo : IMyInterface { }
public class Bar : IMyInterface { }

The downside is that you'll need to know when to use the extension and when not to... Otherwise you can build your own BuilderStrategy.

Heavily influensed by:

Unity - loadConfiguration, how to resolve only those configured

Is there TryResolve in Unity?

Community
  • 1
  • 1
smoksnes
  • 10,509
  • 4
  • 49
  • 74
2

I'm not familiar enough with unity, but you cat start with creating you own configuration, add it as extension:

public class DefaultRegistrationFallbackConfiguration : UnityContainerExtension
{
    protected override void Initialize()
    {
        this.Context.Registering += this.AppendRemapPolicy;
    }

    public override void Remove()
    {
        this.Context.Registering -= this.AppendRemapPolicy;
    }

    private void AppendRemapPolicy(object sender, RegisterEventArgs e)
    {
        if (e.Name != null)
            return;

        if (e.TypeFrom != null && e.TypeTo != null)
            this.Context.Policies.SetDefault<IBuildKeyMappingPolicy>(new MapBuildKeyToDefaultPolicy(e.TypeFrom, e.TypeTo));

        if (e.LifetimeManager == null)
            return;

        throw new NotImplementedException("TODO: lifetime management");
    }
}

Create your own IBuildKeyMappingPolicy:

public class MapBuildKeyToDefaultPolicy : IBuildKeyMappingPolicy
{
    private readonly Type _typeFrom;
    private readonly Type _typeTo;

    public MapBuildKeyToDefaultPolicy(Type typeFrom, Type typeTo)
    {
        this._typeFrom = typeFrom;
        this._typeTo = typeTo;
    }

    public NamedTypeBuildKey Map(NamedTypeBuildKey buildKey, IBuilderContext context)
    {
        if (buildKey.Type == this._typeFrom)
            return new NamedTypeBuildKey(this._typeTo);

        throw new InvalidOperationException();
    }
}

Test classes:

public interface IFoo
{
    void Bar();
}

public class FooNamed : IFoo
{
    public void Bar()
    {
        Console.WriteLine("named one");
    }
}

public class FooDefault : IFoo
{
    public void Bar()
    {
        Console.WriteLine("default one");
    }
}

Test:

public static class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();

        // register extension before use container!
        container.AddExtension(new DefaultRegistrationFallbackConfiguration());

        container.RegisterType(typeof(IFoo), typeof(FooDefault));
        container.RegisterType(typeof(IFoo), typeof(FooNamed), "named");

        container.Resolve<IFoo>()         .Bar(); // default one
        container.Resolve<IFoo>("named")  .Bar(); // named one
        container.Resolve<IFoo>("unknown").Bar(); // default one
    }
}

Output:

default one
named one
default one

lorond
  • 3,856
  • 2
  • 37
  • 52