C# 正在创建运行时模拟:编译Expression.Throw和Expression.Throw后InvalidProgrameException

C# 正在创建运行时模拟:编译Expression.Throw和Expression.Throw后InvalidProgrameException,c#,.net,linq,emit,invalidprogramexception,C#,.net,Linq,Emit,Invalidprogramexception,我正在尝试创建一个运行时模拟,它将为将被调用的每个方法都有一个特定的行为。例如,此模拟应始终返回null(已在运行),或引发无法访问的数据库的异常,或在这种特定情况下引发参数异常。 我知道,用一个模拟框架可以很容易地做到这一点。但是,因为我必须通过Spring.NET使用它,所以据我所知,我不能使用模拟框架。这是因为我必须在StaticApplicationContext中输入一个类型。如果有更简单的方法来创建模拟类型,请告诉我 下面的代码将引发预期的错误: 但是:(公共语言运行库检测到一个无效

我正在尝试创建一个运行时模拟,它将为将被调用的每个方法都有一个特定的行为。例如,此模拟应始终返回null(已在运行),或引发无法访问的数据库的异常,或在这种特定情况下引发参数异常。 我知道,用一个模拟框架可以很容易地做到这一点。但是,因为我必须通过Spring.NET使用它,所以据我所知,我不能使用模拟框架。这是因为我必须在StaticApplicationContext中输入一个类型。如果有更简单的方法来创建模拟类型,请告诉我

下面的代码将引发预期的错误: 但是:(公共语言运行库检测到一个无效程序。) 在TypeMock.Foo()上 在TypeBuilderTest

    public interface IInterfaceWithObject
    {
        String Foo();
    }

    [Test]
    public void MinimalExample()
    {
        //build expression
        var constructorInfo = typeof(ArgumentNullException).GetConstructor(new Type[0]);
        Assert.IsNotNull(constructorInfo);
        Expression expression = Expression.Throw(Expression.New(constructorInfo));

        //create type
        // based upon https://stackoverflow.com/questions/38345486/dynamically-create-a-class-by-interface
        var ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("TestAssembly"), AssemblyBuilderAccess.Run);
        var mb = ab.DefineDynamicModule("Test");

        TypeBuilder typeBuilder = mb.DefineType("TypeMock");

        typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

        typeBuilder.AddInterfaceImplementation(typeof(IInterfaceWithObject));
        List<MethodInfo> methods = new List<MethodInfo>(typeof(IInterfaceWithObject).GetMethods());
        foreach (Type interf in typeof(IInterfaceWithObject).GetInterfaces())
        {
            foreach (MethodInfo method in interf.GetMethods())
                if (!methods.Contains(method))
                    methods.Add(method);
        }
        foreach (var imethod in methods)
        {
            var parameters = imethod.GetParameters();
            List<Type> parameterTypes = new List<Type>();
            foreach (var parameter in parameters)
            {
                parameterTypes.Add(parameter.ParameterType);
            }
            var method =
              typeBuilder.DefineMethod
              (
                "@@" + imethod.Name,
                MethodAttributes.Public | MethodAttributes.Static,
                imethod.ReturnType,
                parameterTypes.ToArray()
              );
            var thisParameter = Expression.Parameter(typeof(IInterfaceWithObject), "this");
            var bodyExpression = Expression.Lambda
                (expression
                    ,
                    thisParameter
                );

            bodyExpression.CompileToMethod(method);
            var stub =
              typeBuilder.DefineMethod(imethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, imethod.ReturnType, parameterTypes.ToArray());
            var il = stub.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.EmitCall(OpCodes.Call, method, null);
            il.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(stub, imethod);
        }
        Type type =  typeBuilder.CreateType();

        //create instance via spring.net
        StaticApplicationContext context = new StaticApplicationContext();
        MutablePropertyValues value = new MutablePropertyValues();
        string objectName = "Integer";
        context.RegisterSingleton(objectName, type, value);
        var objectInstance = (IInterfaceWithObject)context.GetObject(objectName);
        Assert.Throws<ArgumentNullException>(() => objectInstance.Foo());
    }
公共接口IIinterfaceWithObject
{
字符串Foo();
}
[测试]
公共示例()
{
//构建表达式
var constructorInfo=typeof(ArgumentNullException).GetConstructor(新类型[0]);
Assert.IsNotNull(constructorInfo);
Expression=Expression.Throw(Expression.New(constructorInfo));
//创建类型
//基于https://stackoverflow.com/questions/38345486/dynamically-create-a-class-by-interface
var ab=AssemblyBuilder.DefinedDynamicAssembly(新的AssemblyName(“TestAssembly”),AssemblyBuilderAccess.Run);
var mb=ab.DefinedDynamicModule(“测试”);
TypeBuilder TypeBuilder=mb.DefineType(“TypeMock”);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
AddInterfaceImplementation(typeof(IIinterfaceWithObject));
列表方法=新列表(typeof(IInterfaceWithObject.GetMethods());
foreach(typeof(IInterfaceWithObject.GetInterfaces())中的类型interf)
{
foreach(interf.GetMethods()中的MethodInfo方法)
如果(!methods.Contains(method))
方法:添加(方法);
}
foreach(方法中的var i方法)
{
var parameters=imethod.GetParameters();
列表参数类型=新列表();
foreach(参数中的var参数)
{
parameterTypes.Add(parameter.ParameterType);
}
var方法=
typeBuilder.DefineMethod
(
“@@”+i方法名称,
MethodAttributes.Public | MethodAttributes.Static,
i方法返回类型,
parameterTypes.ToArray()
);
var thisParameter=Expression.Parameter(typeof(IInterfaceWithObject),“this”);
var bodyExpression=Expression.Lambda
(表情
,
此参数
);
bodyExpression.CompileToMethod(方法);
var存根=
typeBuilder.DefineMethod(imethod.Name,MethodAttributes.Public | MethodAttributes.Virtual,imethod.ReturnType,parameterTypes.ToArray());
var il=stub.GetILGenerator();
il.Emit(操作码.Ldarg_0);
EmitCall(操作码.Call,方法,null);
发射(操作码Ret);
typeBuilder.DefineMethodOverride(存根,i方法);
}
Type Type=typeBuilder.CreateType();
//通过spring.net创建实例
StaticApplicationContext上下文=新的StaticApplicationContext();
MutablePropertyValues值=新的MutablePropertyValues();
字符串objectName=“Integer”;
RegisterSingleton(objectName、类型、值);
var objectInstance=(IIinterfaceWithObject)context.GetObject(objectName);
抛出(()=>objectInstance.Foo());
}

您能解释一下为什么要针对模拟进行测试吗?仅仅创建一个实现
IInterfaceWithObject
的假(类)不是更容易吗?这会更容易,而且是我目前所做的。但目前我必须为至少五个不同的接口以及不同类型的异常和/或返回值(如null)创建它。这是可能的,但这也是大量重复的代码,这并不是真正必要的。