5

हम एक स्टैंडअलोन कहानी से शुरू करेंगे, इसलिए आप समझते हैं कि क्यों: मैं उसी इंटरफ़ेस के विरुद्ध डेटा बदलने वाले किसी भी क्रिया का इलाज करना चाहता हूं: ICommand ऐसी चीजें हैं जो आईसीएमएंडैंड हैंडलर कहलाती हैं जो मैं चाहता हूं कि किसी भी आदेश को संभाल लें। तो, अगर मैं CreatePersonCommand चाहता हूं तो मुझे वहां CreatePersonCommandHandler की आवश्यकता होगी। जो भी कारण SimpleInjector हमेशा CreateBaseCommand<> मेरे पास है के लिए DeleteCommandHandler<> को हल करने की कोशिश करता है के लिए तो (Simple Injector आवश्यक है)SimpleInjector के साथ RegisterOpenGeneric गलत प्रकार का हल करता है

// 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 
    } 
} 

:

तो यहाँ एक सांत्वना आवेदन के शरीर है कि इस दर्शाता है। फिर से, आदेश कोई फर्क नहीं पड़ता। मेरे पास अन्य, बंद-प्रकार, कमांडहेलर (और उनके संबंधित आदेश) हैं जो केवल ICommandHandler<,> प्राप्त करते हैं जो ठीक काम करते हैं।

मैंने this से प्रत्येक संभावित प्रकार के पंजीकरण के माध्यम से एक अच्छा समय बिताया।

+0

आपके द्वारा सामना की जाने वाली बग वास्तव में परेशान है। मेरे अपने अनुप्रयोगों में से एक में सजावट लिखते समय मैं एक ही समस्या में भाग गया। मैं अगले बगैर (2.4) की प्रतीक्षा करने के बजाय, इस बग को ठीक करने के लिए पैच रिलीज (2.3.6) को रोल करने पर विचार कर रहा हूं, क्योंकि कुछ परिदृश्यों में यह बग के आसपास काम करना वाकई मुश्किल है। – Steven

+0

यह अच्छी खबर है, मैं खुद को अन्य मामलों की उम्मीद नहीं कर रहा था। –

उत्तर

4

अद्यतन:

यह निश्चित रूप से मौजूदा रिलीज में एक बग है। यह किसी भी तरह यूनिट परीक्षण दरारों के माध्यम से फिसल गया। कोड एक चेक को याद करता है जो सत्यापित करता है कि एक निर्मित बंद जेनेरिक कार्यान्वयन वास्तव में अनुरोधित बंद जेनेरिक सेवा प्रकार लागू करता है या नहीं। यदि सभी सामान्य प्रकार की बाधाएं मान्य हैं, तो ढांचा संकल्प को सफल मानता है, जो आपके मामले में गलत है।

फ़िक्स इतना आसान है और आने वाला v2.4 निश्चित रूप से इसे ठीक करेगा, लेकिन इस बीच, आपको निम्न कार्यवाही के साथ पालन करना होगा।

अद्यतन 2:

वास्तव में काफी बुरा है और काफी कुछ मामलों में समाधान करने के लिए कठिन हो सकता है। रजिस्टर ओपेनजेनेरिक के अलावा, सजावटी पंजीकरण भी प्रभावित होते हैं। इससे मुझे निष्कर्ष निकाला गया कि इसे तेजी से तय किया जाना चाहिए और अगली मामूली रिलीज तक इंतजार नहीं कर सकता। इसलिए मैंने Version 2.3.6 को NuGet और CodePlex में धक्का दिया। 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); 
    } 
} 
संबंधित मुद्दे