2012-11-17 45 views
2

我想在簡單的注入器中使用一些不錯的功能。簡單的注入器打開通用裝飾器

我目前有裝修問題,他們也沒有被打到,當我也期待他們。

我註冊它們是這樣的:

container.RegisterManyForOpenGeneric(
     typeof(ICommandHandler<>), 
     AppDomain.CurrentDomain.GetAssemblies()); 

container.RegisterDecorator(
     typeof(ICommandHandler<>), 
     typeof(CreateValidFriendlyUrlCommandHandler<>), 
     context => context.ServiceType == typeof(ICommandHandler<CreateProductCommand>) 
); 

container.RegisterDecorator(
     typeof(ICommandHandler<>), 
     typeof(CreateProductValidationCommandHandler<>), 
     context => context.ServiceType == typeof(ICommandHandler<CreateProductCommand>) 
); 

我想我必須失去了一些東西,因爲我期待,爲ICommandHandler<CreateProductCommand>一個通話會在運行本身之前調用CreateValidFriendlyUrlCommandHandler<>CreateProductValidationCommandHandler<>

我已經嘗試了不同的配準是這樣的:

container.RegisterManyForOpenGeneric(
     typeof(ICommandHandler<>), 
     AppDomain.CurrentDomain.GetAssemblies()); 

container.RegisterDecorator(
     typeof(ICommandHandler<>), 
     typeof(CreateValidFriendlyUrlCommandHandler<>), 
     context => context.ImplementationType == typeof(CreateProductCommandHandler) 
); 

container.RegisterDecorator(
     typeof(ICommandHandler<>), 
     typeof(CreateProductValidationCommandHandler<>), 
     context => context.ImplementationType == typeof(CreateProductCommandHandler) 
); 

正如我認爲在型ICommandHandler<CreateProductCommand>註冊一個裝飾爲ICommandHandler<CreateProductCommand>CreateProductValidationCommandHandlerCreateValidFriendlyUrlCommandHandler實施ICommandHandler<CreateProductCommand>可能擊中位循環引用的。

但改變沒有區別。

這裏是我的CreateProductValidationCommandHandler<TCommand>

public class CreateProductValidationCommandHandler<TCommand> 
    : ICommandHandler<CreateProductCommand> 
{ 
    private readonly ICommandHandler<TCommand> decorated; 
    private readonly IValidationService validationService; 

    public CreateProductValidationCommandHandler(
     ICommandHandler<TCommand> decorated, 
     IValidationService validationService) 
    { 
     this.decorated = decorated; 
     this.validationService = validationService; 
    } 

    public void Handle(CreateProductCommand command) 
    { 
     if (!validationService.IsValidFriendlyName(
      command.Product.ProductFriendlyUrl)) 
     { 
      command.ModelStateDictionary.AddModelError(
       "ProductFriendlyUrl", 
       "The Friendly Product Name is not valid..."); 

      return; 
     } 

     if (!validationService.IsUniqueFriendlyName(
      command.Product.ProductFriendlyUrl)) 
     { 
      command.ModelStateDictionary.AddModelError(
       "ProductFriendlyUrl", 
       "The Friendly Product Name is ..."); 

      return; 
     } 
    } 
} 

這是我CreateValidFriendlyUrlCommandHandler<TCommand>

public class CreateValidFriendlyUrlCommandHandler<TCommand> 
    : ICommandHandler<CreateProductCommand> 
{ 
    private readonly ICommandHandler<TCommand> decorated; 

    public CreateValidFriendlyUrlCommandHandler(ICommandHandler<TCommand> decorated) 
    { 
     this.decorated = decorated; 
    } 

    public void Handle(CreateProductCommand command) 
    { 
     if (string.IsNullOrWhiteSpace(
      command.Product.ProductFriendlyUrl)) 
     { 
      command.Product.ProductFriendlyUrl = 
       MakeFriendlyUrl(command.Product.Name); 
     } 
    } 
} 
+0

你的裝飾器不應該是通用的。事實上,他們在技術上沒有裝飾者:-) – Steven

+0

請注意,'Appdomain.CurrentDomain.GeAssemblies'只返回已經加載的程序集。如果所有實現都與'ICommandHandler '在同一個程序集中,那麼這不會成爲問題,但要小心。 – Steven

回答

3

的問題是,簡單的噴油器將永遠無法包裹的ICommandHandler<T>實現你的裝飾之一,因爲有一個無法解析的通用類型TCommand。如果裝飾器的Handle方法將調用decorated實例,您會注意到這一點。例如:

public class CreateValidFriendlyUrlCommandHandler<TCommand> 
    : ICommandHandler<CreateProductCommand> 
{ 
    private readonly ICommandHandler<TCommand> decorated; 

    public CreateValidFriendlyUrlCommandHandler(
     ICommandHandler<TCommand> decorated) 
    { 
     this.decorated = decorated; 
    } 

    public void Handle(CreateProductCommand command) 
    { 
     // This won't compile since CreateProductCommand and 
     // TCommand are not related. 
     this.decorated.Handle(command); 
    } 
} 

此代碼不能編譯,因爲裝飾的Handle方法接受一個CreateProductCommand說法,而decorated實例需要一個TCommand的說法,這是不指定(和無處說,CreateProductCommandTCommand)。

事實上,你根本沒有創建一個裝飾器。裝飾器包裝它實現的相同接口的一個實例。您在執行ICommandHandler<CreateProductCommand>時包裝ICommandHandler<TCommand>。你會得到這個工作的唯一方法是,當你明確指定TCommand是一個CreateProductCommand,如下所示:

ICommandHandler<CreateProductCommand> handler = 
    new CreateValidFriendlyUrlCommandHandler<CreateProductCommand>(
     new CreateProductCommandHandler() 
    ); 

但是,有沒有辦法簡單的噴油器,以「猜測」,這TCommand應該是一個CreateProductCommand這就是爲什麼你的「裝飾者」沒有被包裝。

長話短說:溝TCommand

public class CreateValidFriendlyUrlCommandHandler 
    : ICommandHandler<CreateProductCommand> 
{ 
    private ICommandHandler<CreateProductCommand> decorated; 

    public CreateValidFriendlyUrlCommandHandler(
     ICommandHandler<CreateProductCommand> decorated) 
    { 
     this.decorated = decorated; 
    } 

    public void Handle(CreateProductCommand command) 
    { 
     // logic here 
    } 
} 

或使其泛型與類型約束:

public class CreateValidFriendlyUrlCommandHandler<TCommand> 
     : ICommandHandler<TCommand> 
     where TCommand : CreateProductCommand 
    { 
     private ICommandHandler<TCommand> decorated; 

     public CreateValidFriendlyUrlCommandHandler(
      ICommandHandler<TCommand> decorated) 
     { 
      this.decorated = decorated; 
     } 

     public void Handle(TCommand command) 
     { 
      // logic here 
     } 
    } 

或刪除類型約束,並允許處理任何類型的命令,不僅CreateProductCommand

請注意,如果您定義了許多隻能處理特定類型命令處理程序的裝飾器,則可能需要重新考慮您的策略。您的設計可能存在問題。

+0

好吧,這是有道理的,我有一些是我試圖讓它工作,因爲我想。我有一個開放的通用註冊,並希望一些裝飾器,但我只希望他們適用於命令是特定類型時。但似乎我以錯誤的方式去了解它。謝謝:) –

+0

現在我醒了我有另一個去它,一旦我停止使用RegisterManyForOpenGeneric並拋棄TCommand建議我現在有它的工作:) –

+0

@DavidMcLean:沒有理由停止使用RegisterManyForOpenGeneric,因爲這個寄存器一次性打開通用接口的所有實現。沒有好的選擇。 – Steven

相關問題