开发者

StructureMap "WithCtorArg" "EqualTo" and nullable types

StructureMap doesn't like passing in Nullable types as constructor arguments. Is there a reason for this? Is there a way to get this to work?

[TestMethod]
public void Demo()
{
    ObjectFactory.Initialize(x => x.ForRequestedType<TestClass>()
                                    .TheDefault.Is.OfConcreteType<TestClass>()开发者_Python百科
                                    .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)
    { }
}


The underlying issue is that there's no difference, from the CLR's perspective, between a boxed (converted to Object) instance of a nullable type, and an (unboxed) instance of the equivalent non-nullable type. Similarly, when you call GetType() on a nullable type like int?, the Type returned is indistinguishable from a regular int. See http://msdn.microsoft.com/en-us/library/ms366789.aspx more info about this.

This behavior is a recipe for disaster for code like StructureMap which interrogates types using GetType() on an Object-typed parameter. Since StructureMap doesn't know whether your byte? is actually nullable, when StructureMap code-gens the constructor call, it code-gens it as a regular byte, which bombs at runtime since StructureMap is passing the wrong type into the constructor call.

It'd be possible for StructureMap to work around this, but the changes would be non-trivial. I tried a few tweaks to the StructureMap source code (e.g. changing from using Object and GetType() to instead using generic methods which accepted a generic parameter type, which could then be interrogated to see if it was a nullable type or not. But there were more changes required (including, AFAIK, in the IL generation required to make the constructor call) and so I gave up.

You might want to bring this up with the Structure Map team itself who knows the code best. The StructureMap Google Group is a reasonable place to start. Note that your question has been asked before (see end of this post) so I'm not sure how responsive the Google Group is.

But, barring a fix in StructureMap itself, if I were you I'd consider wrapping your class in a simple wrapper which removes the need for a nullable parameter in the constructor.

Or if you're feeling brave, you can try to fix this by getting very familiar with the StructureMap source code. :-)

BTW, here's one example where the issue occurs in the StructureMap source:

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

By converting the propertyValue argument to an object, it's impossible for the method to know that it was a nullable type, since byte? and byte are indistinguishable once converted to Object.


I found this code in the StructureMap source. Looks like it's not including nullable types.

protected internal bool IsSimple(Type type)
{
    return type.IsPrimitive || IsString(type) || IsEnum(type);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜