StructureMap & # 8220; WithCtorArg & # 8221; & # 8220; EqualTo & # 8221; y tipos anulables

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

  •  10-07-2019
  •  | 
  •  

Pregunta

A StructureMap no le gusta pasar tipos anulables como argumentos de constructor. ¿Hay alguna razón para esto? ¿Hay alguna manera de hacer que esto funcione?

[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)
    { }
}
¿Fue útil?

Solución

El problema subyacente es que no hay diferencia, desde la perspectiva del CLR, entre una instancia en caja (convertida a Object ) de un tipo anulable y una instancia (sin caja) del equivalente no anulable tipo. Del mismo modo, cuando llama a GetType () en un tipo anulable como int? , el tipo devuelto no se puede distinguir de un int normal. Consulte http://msdn.microsoft.com/en-us/library/ms366789 .aspx más información sobre esto.

Este comportamiento es una receta para el desastre para código como StructureMap que interroga los tipos que usan GetType () en un parámetro de tipo Object. Dado que StructureMap no sabe si su byte? es realmente anulable, cuando StructureMap codifica la llamada del constructor, lo codifica como un byte normal, que bombardea en tiempo de ejecución ya que StructureMap está pasando el tipo incorrecto a la llamada del constructor.

Es posible que StructureMap evite esto, pero los cambios no serían triviales. Intenté algunos ajustes en el código fuente de StructureMap (por ejemplo, cambiar de usar Object y GetType () a usar métodos genéricos que aceptaran un tipo de parámetro genérico, que luego podría ser interrogado para ver si era un tipo anulable o no. fueron necesarios más cambios (incluido AFAIK, en la generación de IL requerida para hacer la llamada al constructor) y así me di por vencido.

Es posible que desee mencionar esto con el equipo de Structure Map que conoce mejor el código. El Grupo de Google StructureMap es un lugar razonable para comenzar. Tenga en cuenta que su pregunta ya se ha hecho antes (consulte el final de esta publicación ), así que no estoy seguro de qué tan receptivo es el Grupo de Google.

Pero, salvo una solución en el propio StructureMap, si fuera usted, consideraría ajustar su clase en un contenedor simple que elimine la necesidad de un parámetro anulable en el constructor.

O si te sientes valiente, puedes intentar solucionarlo familiarizándote con muy el código fuente de StructureMap. :-)

Por cierto, aquí hay un ejemplo donde el problema ocurre en la fuente de 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;
    }

Al convertir el argumento propertyValue en un objeto, es imposible que el método sepa que era un tipo anulable, ya que byte? y byte son indistinguibles una vez convertidos a Objeto.

Otros consejos

Encontré este código en la fuente de StructureMap. Parece que no incluye tipos anulables.

protected internal bool IsSimple(Type type)
{
    return type.IsPrimitive || IsString(type) || IsEnum(type);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top