如何在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 { } }
修正后的代码及说明
核心问题点修正:
CreateViewModel<T>必须实现IService接口:原代码中CreateViewModel没有实现IService,导致GetRequiredService返回的实例无法调用Invoke方法。- 反射调用后需执行
Invoke方法:原代码直接将GetRequiredService的返回值转为IViewModel,但实际上该方法返回的是IService实例,需要调用其Invoke才能得到ViewModel。 - 简化
_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
相关产品推荐
相关产品推荐

