模拟框架无法处理通用引用类型参数

时间:2014-04-15 15:51:57

标签: c# reflection mocking tdd il

我们一直使用Simple.Mocking作为单元测试的模拟框架。最近,我对 ICacheService 进行了更改,这在我们的单元测试和模拟中大量使用。

我所做的更改是添加类似于以下的方法:

bool TrySetCache(string key,T data,ref T value);

此实现的语义无关紧要,因此请不要提供有关引用类型参数使用的反馈。 :)

一旦我们的CI构建启动并运行我们的自动化测试,它们都会因模拟类型创建失败而失败。

我深入研究了这个项目,并意识到它在尝试模拟通用引用类型参数时失败了。

以下coee处理为模拟方法参数发出IL:

var baseMethodParameters = baseMethod.GetParameters();

        ilGenerator.Emit(OpCodes.Ldc_I4, baseMethodParameters.Length);
        ilGenerator.Emit(OpCodes.Newarr, typeof(object));
        ilGenerator.Emit(OpCodes.Stloc_2);

        for (int i = 0; i < baseMethodParameters.Length; i++)
        {
            var parameter = baseMethodParameters[i];

            var parameterType = parameter.ParameterType;

            ilGenerator.Emit(OpCodes.Ldloc_2);
            ilGenerator.Emit(OpCodes.Ldc_I4, i);

            ilGenerator.Emit(OpCodes.Ldarg, i + 1);

            if (parameterType.IsByRef)
            {
                parameterType = parameterType.GetRealTypeForByRefType();
                ilGenerator.EmitLoadIndirect(parameterType);
            }

            EmitBoxValue(ilGenerator, parameterType);

            ilGenerator.Emit(OpCodes.Stelem_Ref);
        }

更具体地说,处理reference-type参数的代码:

if (parameterType.IsByRef)
            {
                parameterType = parameterType.GetRealTypeForByRefType();
                ilGenerator.EmitLoadIndirect(parameterType);
            }

当使用通用引用类型参数时,这将调用失败的扩展方法:

const string ByRefSpecifier = "&";

    public static Type GetRealTypeForByRefType(this Type type)
    {
        if (!type.IsByRef)
            throw new InvalidOperationException();

        return Type.GetType(type.AssemblyQualifiedName.Replace(ByRefSpecifier, string.Empty), true);
    }

return语句失败。

我想解决这个问题,但我不确定它是否可以推断使用情况并模拟通用引用类型参数。

如果它实际上是不可能的,那么我最后会添加一个检查以查看它是否是泛型类型参数,如果是,则给出错误消息,以便用户不需要进行太长时间的故障排除找出问题。

重要提示我在调试时注意到的一件事是当它反映在我的ICacheService.TrySetCache(字符串键,T数据,ref T值)时,它没有标记最后一个参数作为通用参数类型。

1 个答案:

答案 0 :(得分:1)

由于您的类型是通用参数,AssemblyQualifiedName将为null。相反,parameterType.GetRealTypeForByRefType()几乎肯定会被parameterType.GetElementType()替换。