ekonbenefits / impromptu-interface

Static interface to dynamic implementation (duck casting). Uses the DLR combined with Reflect.Emit.
Apache License 2.0
655 stars 67 forks source link

Failure when using generic structs in nullable contexts #56

Open Methuselah96 opened 8 months ago

Methuselah96 commented 8 months ago

Starting in v8, an exception is thrown when trying to use ActLike on an interface with a property that is a generic struct in a nullable context.

Here is the example code:

#nullable enable

public struct GenericStruct<T>
{
    public string Something { get; }

    public GenericStruct(string something)
    {
        Something = something;
    }
}

public interface IInterfaceWithGenericStructProperty
{
    GenericStruct<IInterfaceWithGenericStructProperty> StructProperty { get; }

    string SomeOtherProperty { get; }
}

And the corresponding test:

[Test]
public void GenericStructInNullableContextTest()
{
    var result = new
    {
        SomeOtherProperty = "test"
    }.ActLike<IInterfaceWithGenericStructProperty>();
}

The exception:

Message:
System.InvalidCastException : Unable to cast object of type 'System.Collections.ObjectModel.ReadOnlyCollection`1[System.Reflection.CustomAttributeTypedArgument]' to type 'System.Array'.

Stack Trace:
CustomAttributeBuilder.EmitValue(BinaryWriter writer, Type type, Object value)
CustomAttributeBuilder.ctor(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues, FieldInfo[] namedFields, Object[] fieldValues)
ActLikeMaker.ToCustomAttributeBuilder(CustomAttributeData customAttributeData) line 1434
ActLikeMaker.EmitProperty(TypeBuilder typeBuilder, MethodBuilder getMethodBuilder, PropertyBuilder tMp, PropertyInfo info, MethodBuilder setMethodBuilder, PropertyEmitInfo emitInfo) line 1580
ActLikeMaker.MakePropertyHelper(ModuleBuilder builder, TypeBuilder typeBuilder, PropertyEmitInfo emitInfo, PropertyInfo info) line 1380
ActLikeMaker.MakeProperty(ModuleBuilder builder, PropertyInfo info, TypeBuilder typeBuilder, Type contextType, Boolean nonRecursive, Boolean defaultImp) line 875
ActLikeMaker.BuildTypeHelper(ModuleBuilder builder, Type contextType, Type[] interfaces) line 446
ActLikeMaker.BuildType(Type contextType, Type mainInterface, Type[] otherInterfaces) line 200
ActLikeMaker.ActLike[TInterface](Object originalDynamic, Type[] otherInterfaces) line 90
Impromptu.ActLike[TInterface](Object originalDynamic, Type[] otherInterfaces) line 39
Basic.GenericStructInNullableContextTest() line 661

I suspect this may be caused by https://github.com/ekonbenefits/impromptu-interface/pull/49, since the code path that is generating the exception is first introduced in that PR.

See https://github.com/ekonbenefits/impromptu-interface/pull/57 for a fix.

HowardvanRooijen commented 1 week ago

I don't suppose this is going to be resolved soon?