StructureMap & # 8220; WithCtorArg & # 8221; & # 8220; equalTo & # 8221; e tipi nullable

StackOverflow https://stackoverflow.com/questions/1645305

  •  10-07-2019
  •  | 
  •  

Domanda

A StructureMap non piace passare i tipi Nullable come argomenti del costruttore. C'è una ragione per questo? C'è un modo per farlo funzionare?

[TestMethod]
public void Demo()
{
    ObjectFactory.Initialize(x => x.ForRequestedType<TestClass>()
                                    .TheDefault.Is.OfConcreteType<TestClass>()
                                    .WithCtorArg("param1").EqualTo((byte?)3));

//This fails, but works if it's non-nullable
    var result = ObjectFactory.GetInstance<TestClass>();
}

public class TestClass
{
    public TestClass(byte? param1)
    { }
}
È stato utile?

Soluzione

Il problema di fondo è che non vi è alcuna differenza, dal punto di vista del CLR, tra un'istanza in box (convertita in Object ) di tipo nullable e un'istanza (unboxed) dell'equivalente non nullable genere. Allo stesso modo, quando si chiama GetType () su un tipo nullable come int? , il tipo restituito è indistinguibile da un normale int . Vedi http://msdn.microsoft.com/en-us/library/ms366789 .aspx maggiori informazioni al riguardo.

Questo comportamento è una ricetta per il disastro di codice come StructureMap che interroga i tipi usando GetType () su un parametro tipizzato ad oggetto. Dato che StructureMap non sa se il tuo byte? è effettivamente nullable, quando StructureMap codifica la chiamata del costruttore, lo codifica come un normale byte , che bombe a runtime poiché StructureMap sta passando il tipo errato nella chiamata del costruttore.

Sarebbe possibile per StructureMap aggirare questo problema, ma le modifiche non sarebbero banali. Ho provato alcune modifiche al codice sorgente di StructureMap (ad esempio passando dall'uso di Object e GetType () a invece di utilizzare metodi generici che hanno accettato un tipo di parametro generico, che potrebbe quindi essere interrogato per vedere se fosse un tipo nullable o no. sono stati richiesti più cambiamenti (incluso, AFAIK, nella generazione IL richiesta per chiamare il costruttore) e così ho rinunciato.

Potresti volerlo presentare allo stesso team di Structure Map che conosce meglio il codice. Il StructureMap Google Group è un punto di partenza ragionevole. Tieni presente che la tua domanda è stata posta in precedenza (vedere la fine di questo post ), quindi non sono sicuro di quanto sia reattivo il Gruppo Google.

Ma, escludendo una correzione in StructureMap stessa, se fossi in te prenderei in considerazione il wrapping della tua classe in un semplice wrapper che elimina la necessità di un parametro nullable nel costruttore.

O se ti senti coraggioso, puoi provare a risolvere questo problema acquisendo molto familiarità con il codice sorgente di StructureMap. : -)

A proposito, ecco un esempio in cui si verifica il problema nell'origine StructureMap:

    /// <summary>
    /// Sets the value of the constructor argument
    /// </summary>
    /// <param name="propertyValue"></param>
    /// <returns></returns>
    public T EqualTo(object propertyValue)
    {
        if(propertyValue.GetType().IsSimple())
            _instance.SetProperty(_propertyName, propertyValue.ToString());
        else
        {
            _instance.SetChild(_propertyName,new LiteralInstance(propertyValue));
        }
        return (T) _instance;
    }

Convertendo l'argomento propertyValue in un oggetto, è impossibile per il metodo sapere che era un tipo nullable, poiché byte? e byte sono indistinguibili una volta convertiti in oggetto.

Altri suggerimenti

Ho trovato questo codice nella fonte StructureMap. Sembra che non includa tipi nullable.

protected internal bool IsSimple(Type type)
{
    return type.IsPrimitive || IsString(type) || IsEnum(type);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top