Зарегистрировать и разрешить общие объекты - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть некоторые проблемы с Зарегистрировать мои интерфейсы.У меня есть следующие интерфейсы:

public interface IMapper<Q, T> { /* Mapper Helper Methods */ }
public interface ISourceObject { /* Properties */ }
public interface ITargetObject { /* Properties */ }

Реализации:

public class GenericMapper<Q, T> : IMapper<Q,T> { /* Mapper Helper Methods */ }
public class SourceObject : ISourceObject { /* Properties */ }
public class TargetObject : ITargetObject { /* Properties */ }

В моем модуле Autofac я хочу зарегистрировать его следующим образом:

builder.RegisterType<GenericMapper<SourceObject, TargetObject>>().As<IMapper<ISourceObject, ITargetObject>>();

Иразрешите его с помощью:

Container.Resolve<IMapper<ISourceObject, ITargetObject>>();

Конфигурация профиля Automapper:

CreateMap<ISourceObject, ITargetObject>()
                    // ForMember Mappings
.ForAllMembers(o => o.Condition((src, dest, value) => value != null));

Когда я запускаю свой Unittest, он падает со следующей трассировкой стека:

at Autofac.Builder.RegistrationBuilder.CreateRegistration(Guid id, RegistrationData data, IInstanceActivator activator, IEnumerable`1 services, IComponentRegistration target)
   at Autofac.Builder.RegistrationBuilder.CreateRegistration[TLimit,TActivatorData,TSingleRegistrationStyle](IRegistrationBuilder`3 builder)
   at Autofac.Builder.RegistrationBuilder.RegisterSingleComponent[TLimit,TActivatorData,TSingleRegistrationStyle](IComponentRegistry cr, IRegistrationBuilder`3 builder)
   at Autofac.RegistrationExtensions.<>c__DisplayClass3_0`1.<RegisterType>b__0(IComponentRegistry cr)
   at Autofac.ContainerBuilder.Build(IComponentRegistry componentRegistry, Boolean excludeDefaultModules)
   at Autofac.ContainerBuilder.Build(ContainerBuildOptions options)

System.ArgumentException: 
    System.ArgumentException: The type 'App.Test.Models.GenericMapper`2[App.Test.Models.SourceObject,App.Test.Models.TargetObject]' is not assignable 
    to service 'App.Test.Models.IMapper`2[[App.Test.Models.ISourceObject, App.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],
    [App.Test.Models.ITargetObject, App.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'..

Что я здесь не так?Когда я регистрирую реализации, решение работает без проблем.Но это было бы жестко связано с реализациями, и это, я не хочу.Могу ли я решить эту проблему таким образом, или мне нужно использовать версию с проводным подключением?

1 Ответ

0 голосов
/ 22 февраля 2019

У вас проблема с определениями вашего интерфейса.Если вы полностью извлекаете Autofac из микса и просто тестируете его вручную, вы можете увидеть доказательства:

[Fact]
public void TypesAreCompatible()
{
    var init = new GenericMapper<SourceObject, TargetObject>();
    var cast = (IMapper<ISourceObject, ITargetObject>)init;
    Assert.Same(init, cast);
}

Это приведет к ошибке в строке, начинающейся с var cast, и выдаст исключение:

System.InvalidCastException : Unable to cast object of type 'GenericMapper`2[SourceObject,TargetObject]' to type 'IMapper`2[ISourceObject,ITargetObject]'.

Причина в том, что ваш IMapper интерфейс не является ковариантным . Проще говоря, это означает, что вы не можете поместить более производное введите Q или T и сделайте так, чтобы это «волшебно работало».Это должно быть точно.

Обновите ваш интерфейс, чтобы сообщить C #, что можно использовать ковариантные типы, поставив out перед параметрами типа.

public interface IMapper<out Q, out T> { }

Как только вы это сделаете, тест, который я поставил выше, будет работать ... и регистрация Autofac тоже.

...