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

如何在C#中通过反射调用嵌套泛型类型的方法?

反射调用嵌套泛型方法的问题修正

我找到了一些反射调用泛型方法(如method<T>())的示例,但我的场景是泛型类型嵌套在类中,即method<Class<T>>()。

在WPF应用里,我需要根据View枚举切换对应的ViewModel,枚举项和ViewModel数量一一对应。随着视图/ViewModel不断新增,我想避免重复写switch分支的代码。_serviceProvider是Microsoft Dependency Injection提供的实例。

原有重复代码

switch (view)
{
    case View.Settings:
        ViewModel = _serviceProvider.GetRequiredService<CreateViewModel<SettingsViewModel>>().Invoke();
        break;
    // ... 新增视图就要加新的case分支
}

我尝试的代码(待修正)

using System;
using System.Reflection;

namespace NestedGenericReflection
{
    class Program
    {
        private static ServiceProviderModel _serviceProvider = new ServiceProviderModel();

        static void Main(string[] args)
        {
            var view = View.Settings;

            IViewModel viewModel = null;

            var assembly = typeof(IViewModel).Assembly;

            var typeName = $"NestedGenericReflection.{view}ViewModel, {assembly.FullName}";

            var type = Type.GetType(typeName);

            var generic = typeof(CreateViewModel<>).MakeGenericType(type); // 我认为这部分不正确..

            var field = typeof(Program).GetField(nameof(_serviceProvider), BindingFlags.NonPublic | BindingFlags.Static); // 示例中为静态字段

            var method = field.FieldType
                              .GetMethod("GetRequiredService")
                              .MakeGenericMethod(generic);

            viewModel = method.Invoke(_serviceProvider, null) as IViewModel;
        }
    }

    public enum View
    {
        Settings
    }

    public interface IViewModel
    {

    }

    public interface IService
    {
        IViewModel Invoke();
    }

    public class ServiceProviderModel
    {
        public IService GetRequiredService<T>()
        {
            return null;
        }
    }

    public class SettingsViewModel : IViewModel
    {

    }

    public class CreateViewModel<ViewModel> where ViewModel : class
    {

    }
}

修正后的代码及说明

核心问题点修正:

  1. CreateViewModel<T>必须实现IService接口:原代码中CreateViewModel没有实现IService,导致GetRequiredService返回的实例无法调用Invoke方法。
  2. 反射调用后需执行Invoke方法:原代码直接将GetRequiredService的返回值转为IViewModel,但实际上该方法返回的是IService实例,需要调用其Invoke才能得到ViewModel。
  3. 简化_serviceProvider的获取:示例中_serviceProvider是静态字段,无需通过反射获取,直接使用即可。
using System;
using System.Reflection;

namespace NestedGenericReflection
{
    class Program
    {
        private static ServiceProviderModel _serviceProvider = new ServiceProviderModel();

        static void Main(string[] args)
        {
            var view = View.Settings;
            IViewModel viewModel = null;

            var assembly = typeof(IViewModel).Assembly;
            // 构造ViewModel的完整类型名
            var typeName = $"NestedGenericReflection.{view}ViewModel, {assembly.FullName}";
            var viewModelType = Type.GetType(typeName);

            if (viewModelType == null)
            {
                throw new InvalidOperationException($"找不到ViewModel类型:{typeName}");
            }

            // 创建嵌套泛型类型 CreateViewModel<SettingsViewModel>
            var createViewModelType = typeof(CreateViewModel<>).MakeGenericType(viewModelType);

            // 获取GetRequiredService泛型方法并指定泛型参数
            var getServiceMethod = typeof(ServiceProviderModel)
                .GetMethod(nameof(ServiceProviderModel.GetRequiredService))
                .MakeGenericMethod(createViewModelType);

            // 调用方法获取IService实例
            var service = getServiceMethod.Invoke(_serviceProvider, null) as IService;

            if (service == null)
            {
                throw new InvalidOperationException($"无法获取服务:{createViewModelType.FullName}");
            }

            // 调用Invoke得到最终的ViewModel
            viewModel = service.Invoke();

            Console.WriteLine($"成功获取ViewModel:{viewModel.GetType().Name}");
        }
    }

    public enum View
    {
        Settings
    }

    public interface IViewModel { }

    public interface IService
    {
        IViewModel Invoke();
    }

    // 模拟Microsoft DI的ServiceProvider行为
    public class ServiceProviderModel
    {
        public IService GetRequiredService<T>()
        {
            // 实际项目中替换为_serviceProvider.GetRequiredService<T>()
            // 这里模拟实例化CreateViewModel<T>
            return Activator.CreateInstance<T>() as IService;
        }
    }

    public class SettingsViewModel : IViewModel { }

    // 让CreateViewModel实现IService,并在Invoke中获取ViewModel
    public class CreateViewModel<ViewModel> : IService where ViewModel : class, IViewModel
    {
        // 实际项目中通过构造函数注入IServiceProvider或直接注入ViewModel
        private readonly IServiceProvider _serviceProvider;

        public CreateViewModel(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public IViewModel Invoke()
        {
            // 从DI获取ViewModel实例
            return _serviceProvider.GetRequiredService<ViewModel>();
        }

        // 为了模拟示例,添加无参构造函数
        public CreateViewModel() { }
    }
}

实际WPF项目中的注意事项:

  • 确保所有ViewModel都实现IViewModel接口,且命名严格遵循{View枚举项}ViewModel的规则。
  • 实际使用时,ServiceProviderModel替换为Microsoft DI的IServiceProvider,无需自己模拟。
  • 可以将反射逻辑封装成一个工具方法,方便在多个地方调用,进一步减少重复代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 00:43:11