You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# 如何通过反射将对象强制转换为其隐式实现的接口类型

C# 运行时不支持为已创建的实例动态追加接口实现,你可以通过适配器或动态代理的方式包装现有 Mock 实例,上层业务代码无需任何修改即可正常使用,以下是两种常用实现方案:

方案1:手写适配器(无额外依赖,适合少量标记接口场景)

仅需新增一个适配器类,把所有接口方法转发到内部的 MockRepository<Email> 实例即可:

public class EmailRepositoryAdapter : IEmailRepository
{
    private readonly IRepository<Email> _innerRepository;

    public EmailRepositoryAdapter(IRepository<Email> innerRepository)
    {
        _innerRepository = innerRepository;
    }

    // 转发所有IRepository<Email>定义的方法
    public void Save(Email entity) => _innerRepository.Save(entity);
}

使用方式:

MockRepository<Email> mockRepository = CreateMockRepository<Email>();
IEmailRepository mockedEmailRepository = new EmailRepositoryAdapter(mockRepository);
SomeBusinessMethod(mockedEmailRepository);

方案2:运行时动态生成通用适配器(适合大量同类标记接口场景)

如果项目中存在大量类似的空标记仓储接口,可以用反射发射实现通用适配逻辑,避免逐个编写适配器类:

using System.Reflection;
using System.Reflection.Emit;

public static class RepositoryAdapterGenerator
{
    public static TInterface Adapt<TInterface, TEntity>(IRepository<TEntity> innerRepository)
        where TInterface : IRepository<TEntity>
    {
        // 定义动态程序集和模块
        var assemblyName = new AssemblyName($"DynamicAdapter_{Guid.NewGuid():N}");
        var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);

        // 定义适配器类
        var typeName = $"{typeof(TInterface).Name}_Adapter";
        var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
        
        // 声明内部仓储字段
        var innerField = typeBuilder.DefineField("_inner", typeof(IRepository<TEntity>), FieldAttributes.Private);
        
        // 实现构造函数,注入内部仓储实例
        var ctorBuilder = typeBuilder.DefineConstructor(
            MethodAttributes.Public, 
            CallingConventions.Standard, 
            new[] { typeof(IRepository<TEntity>) });
        var ilGenerator = ctorBuilder.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.Emit(OpCodes.Ldarg_1);
        ilGenerator.Emit(OpCodes.Stfld, innerField);
        ilGenerator.Emit(OpCodes.Ret);

        // 实现目标标记接口
        typeBuilder.AddInterfaceImplementation(typeof(TInterface));

        // 转发所有接口方法到内部仓储实例
        var interfaceMethods = typeof(TInterface)
            .GetInterfaces()
            .Concat(new[] { typeof(TInterface) })
            .SelectMany(x => x.GetMethods());
        
        foreach (var interfaceMethod in interfaceMethods)
        {
            var parameters = interfaceMethod.GetParameters();
            var methodBuilder = typeBuilder.DefineMethod(
                interfaceMethod.Name,
                MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
                interfaceMethod.ReturnType,
                parameters.Select(p => p.ParameterType).ToArray());
            
            var methodIl = methodBuilder.GetILGenerator();
            methodIl.Emit(OpCodes.Ldarg_0);
            methodIl.Emit(OpCodes.Ldfld, innerField);
            for (var i = 0; i < parameters.Length; i++)
            {
                methodIl.Emit(OpCodes.Ldarg, i + 1);
            }
            methodIl.Emit(OpCodes.Callvirt, interfaceMethod);
            methodIl.Emit(OpCodes.Ret);
            
            typeBuilder.DefineMethodOverride(methodBuilder, interfaceMethod);
        }

        // 创建实例并返回
        var adapterType = typeBuilder.CreateType();
        return (TInterface)Activator.CreateInstance(adapterType, innerRepository);
    }
}

使用方式:

MockRepository<Email> mockRepository = CreateMockRepository<Email>();
IEmailRepository mockedEmailRepository = RepositoryAdapterGenerator.Adapt<IEmailRepository, Email>(mockRepository);
SomeBusinessMethod(mockedEmailRepository);

两种方案都不需要修改现有业务逻辑代码,仅需在模拟仓储注入的环节做一层包装即可。如果使用依赖注入容器,可直接在服务注册逻辑中完成适配,业务侧完全无感知。

内容的提问来源于stack exchange,提问作者Tvde1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 16:54:02