5

이유를 이해 한 이유는 다음과 같습니다. 동일한 인터페이스에 대해 데이터를 변경하는 작업을 처리하고 싶습니다. ICommand ICommandHandlers 그 명령은 내가 원하는 명령을 처리합니다. 그래서 CreatePersonCommand를 원한다면 CreatePersonCommandHandler가 필요합니다. SimpleInjector 항상 내가 가지고있는 CreateBaseCommand<>에 대한 DeleteCommandHandler<>를 해결하려고 어떤 이유 그래서RegisterInpenGeneric with SimpleInjector가 잘못된 유형을 해결합니다.

// The e.g. CreatePersonCommand, with TResult being Person, as an example. 
public interface ICommand<TResult> 
{ 
} 

//This handles the command, so CreatePersonCommandHandler 
public interface ICommandHandler<in TCommand, out TResult> 
    where TCommand : ICommand<TResult> 
{ 
    TResult Handle(TCommand command); 
} 

// Imagine a generic CRUD set of operations here where we pass 
// in an instance of what we need made 
public class CreateBaseCommand<TModel> : ICommand<TModel> 
{ 
    public TModel ItemToCreate { get; set; } 
} 

public class DeleteBaseCommand<TModel> : ICommand<TModel> 
{ 
    public TModel ItemToDelete { get; set; } 
} 

public class CreateCommandBaseHandler<TModel> 
    : ICommandHandler<CreateBaseCommand<TModel>, TModel> 
{ 
    public TModel Handle(CreateBaseCommand<TModel> command) 
    { 
     // create the thing 
     return default (TModel); 
    } 
} 

public class DeleteCommandBaseHandler<TModel> 
    : ICommandHandler<DeleteBaseCommand<TModel>, TModel> 
{ 
    public TModel Handle(DeleteBaseCommand<TModel> command) 
    { 
     // delete the thing 
     return default(TModel); 
    } 
} 

public class Program 
{ 
    private static Container container; 

    static void Main(string[] args) 
    { 
     container = new Container(); 

     // Order does not seem to matter, I've tried both ways. 
     container.RegisterOpenGeneric(typeof(ICommandHandler<,>), 
      typeof(DeleteCommandBaseHandler<>)); 
     container.RegisterOpenGeneric(typeof(ICommandHandler<,>), 
      typeof(CreateCommandBaseHandler<>)); 

     container.Verify(); 

     // So I want to make the usual hello world 
     var commandToProcess = new CreateBaseCommand<string> { ItemToCreate = "hello world"}; 

     // Send it away! 
     Send(commandToProcess); 
    } 

    private static void Send<TResult>(ICommand<TResult> commandToProcess) 
    { 
     //{CreateBaseCommand`1[[System.String,..."} 
     var command = commandToProcess.GetType(); 
     //{Name = "String" FullName = "System.String"} 
     var resultType = typeof (TResult); 

     //"ICommandHandler`2[[CreateBaseCommand`1[[System.String,..."} 
     // so it's the right type here 
     var type = typeof(ICommandHandler<,>).MakeGenericType(command, resultType); 

     // This is where we break! 
     var instance = container.GetInstance(type); 
     // The supplied type DeleteCommandBaseHandler<String> does not implement 
     // ICommandHandler<CreateBaseCommand<String>, String>. 
     // Parameter name: implementationType 
    } 
} 

을 (Simple Injector 필요) :

그래서 여기 보여줍니다 콘솔 응용 프로그램의 몸입니다. 다시 말해서 순서는 중요하지 않습니다. 나는 잘 작동하는 ICommandHandler<,>을 상속받은 폐쇄 형 명령 핸들러 (및 해당 명령)가 있습니다.

나는 가능한 모든 유형의 등록을 수행하는 데 많은 시간을 할애하여 this에서 할 수있었습니다.

+0

발생한 버그는 실제로 귀찮습니다. 내 응용 프로그램 중 하나에 데코레이터를 작성할 때 동일한 문제가 발생했습니다. 몇 가지 시나리오에서이 버그를 해결하기가 정말 어렵 기 때문에 다음 번 미성년자 (2.4)를 기다리는 대신이 버그를 수정하기 위해 패치 릴리스 (2.3.6)를 배포 할 것을 고려하고 있습니다. – Steven

+0

그건 좋은 소식인데, 나는 다른 사건을 직접 바라지 않았다. –

답변

4

UPDATE :

이 확실히 현재 버전에서 버그입니다. 이것은 어떻게 든 단위 테스트 균열을 빠져 나갔습니다. 이 코드는 빌드 된 일반 구현체가 요청 된 닫힌 제네릭 서비스 유형을 실제로 구현하는지 여부를 확인하는 검사를 누락합니다. 모든 제네릭 형식 제약 조건이 유효하면 프레임 워크는 해결 방법을 성공으로 간주합니다. 이는 잘못된 경우입니다.

수정이 쉽고 앞으로 v2.4에서 확실히이 문제가 해결되지만 그 동안 다음 해결 방법을 사용해야합니다.

업데이트 2 :

(가) 실제로는 매우 불쾌한이며, 경우에 따라서 해결하는 것은 매우 어려울 수 있습니다. RegisterOpenGeneric 외에도, 데코레이터 등록도 영향을받습니다. 이로 인해이 문제는 신속하게 해결되어야하고 다음 사소한 릴리스까지 기다릴 수 없다는 결론을 내 렸습니다. 따라서 NuGet과 CodePlex에 Version 2.3.6을 푸시했습니다. v2.3.6에서는이 문제를 해결합니다.

해결 방법 :

해결 방법은 (예 : DeleteBaseCommand<TModel> 같은) 다른 유형으로 중첩 된 공급 제네릭 형식 인수를 방지하는 것입니다. 대신 다음 예제에서 볼 수 있듯이 대신 일반 유형 제약 조건을 사용할 수 있습니다.

public class CreateCommandBaseHandler<TCommand, TModel> 
    : ICommandHandler<TCommand, TModel> // no nested generic arguments here 
    where TCommand : CreateBaseCommand<TModel> // but type constraint here. 
{ 
    public TModel Handle(TCommand command) 
    { 
     // create the thing 
     return default(TModel); 
    } 
} 

public class DeleteCommandBaseHandler<TCommand, TModel> 
    : ICommandHandler<TCommand, TModel> 
    where TCommand : DeleteBaseCommand<TModel> 
{ 
    public TModel Handle(TCommand command) 
    { 
     // delete the thing 
     return default(TModel); 
    } 
} 
관련 문제