获取泛型方法的 T 类型的具体类型
Getting concrete type of generic method's T type
我确定之前有人问过这个问题,但我似乎无法找到我正在寻找的解决方案,尽管搜索了很长时间 SO/Google,所以希望你能回答我的问题。
为简洁起见,假设我有以下对象:
public interface ISectionView { }
public class SampleSectionView : ISectionView { }
public interface ISectionService<T> where T : ISectionView { }
public class SampleSectionService : ISectionService<SampleSectionView>
现在我的控制器中有以下代码:
ISectionView sectionType = new SampleSectionView(); // *** NOTE THE TYPE
var service = _serviceResolver.Resolve(sectionType);
为此,_serviceResolver.Resolve 方法如下所示:
public ISectionService<V> Resolve<V>(V sectionViewModel)
where V : ISectionView
{
var sectionViewModelTypeName = sectionViewModel.GetType().Name;
// Ignore this, it's some AutoFac metadata resolution
var resolvableService = _services.FirstOrDefault(s => s.Matches(sectionViewModelTypeName));
if (resolvableService != null)
return resolvableService.Value as ISectionService<V>; // Upcast, as this is the actual type we want!
return null;
}
因此,正如我们在上面看到的,我在我的控制器中创建了 sectionType 变量作为 ISectionView 类型,SampleSectionView 实现了该类型。这导致我在 resolve 方法中出现问题,因为它实际上在做什么(正如我在即时 Window 中检查过的)如下:
return resolvableService.Value as ISectionService<ISectionView>;
这是个问题,因为我的服务要转换为以下内容:
return resolvableService.Value as ISectionService<SampleSectionView>;
我知道我已将一个 SampleSectionView 对象传递给此解析方法,但基于通用 V 类型参数的转换有点丢失。
那么我怎样才能让转换识别实际的具体类型,而不是创建它的接口类型?
郑重声明,我知道我可以做到以下几点:
var sectionType = new SampleSectionView();
但这是一个问题,因为我需要一个工厂方法来创建 ISectionView,所以我知道这是我传递给 Resolve 的类型。是的,我明白为什么这是一个问题,那么可以做些什么来克服这个问题呢?如果可能的话,我宁愿 而不是 有一个 switch/case 语句来处理转换。
谢谢
回答
感谢所有评论。最后,我所要做的就是将 ISectionService 接口修改为以下内容:
public interface ISectionService<out T> where T : ISectionView { }
这就足够了。
接口不能以这种方式工作,让接口 IInterface<IBase>
转换为 IInterface<IDerived>
的唯一方法是使用 out
参数声明接口。
我建议阅读此 question 中的答案。我相信它会为您提供所需的信息。
我不确定这是最好的解决方案,但您可以将其包装到 non-generic 带反射的方法中。
class ServiceResolver
{
public ISectionService<ISectionView> ResolveNonGeneric(ISectionView sectionViewModel)
{
var method = GetType()
.GetMethod(nameof(Resolve), BindingFlags.Public | BindingFlags.Instance)
.MakeGenericMethod(sectionViewModel.GetType());
return (ISectionService<ISectionView>) method.Invoke(this, new[] { sectionViewModel });
}
public ISectionService<V> Resolve<V>(V sectionViewModel) where V : ISectionView
{
//V is SampleSectionView
}
}
从而执行:
ISectionView sectionType = new SampleSectionView();
var service = _serviceResolver.ResolveNonGeneric(sectionType);
将在内部执行Resolve<SampleSectionView>
。
虽然这需要使 ISectionService<T>
协变。
我确定之前有人问过这个问题,但我似乎无法找到我正在寻找的解决方案,尽管搜索了很长时间 SO/Google,所以希望你能回答我的问题。
为简洁起见,假设我有以下对象:
public interface ISectionView { }
public class SampleSectionView : ISectionView { }
public interface ISectionService<T> where T : ISectionView { }
public class SampleSectionService : ISectionService<SampleSectionView>
现在我的控制器中有以下代码:
ISectionView sectionType = new SampleSectionView(); // *** NOTE THE TYPE
var service = _serviceResolver.Resolve(sectionType);
为此,_serviceResolver.Resolve 方法如下所示:
public ISectionService<V> Resolve<V>(V sectionViewModel)
where V : ISectionView
{
var sectionViewModelTypeName = sectionViewModel.GetType().Name;
// Ignore this, it's some AutoFac metadata resolution
var resolvableService = _services.FirstOrDefault(s => s.Matches(sectionViewModelTypeName));
if (resolvableService != null)
return resolvableService.Value as ISectionService<V>; // Upcast, as this is the actual type we want!
return null;
}
因此,正如我们在上面看到的,我在我的控制器中创建了 sectionType 变量作为 ISectionView 类型,SampleSectionView 实现了该类型。这导致我在 resolve 方法中出现问题,因为它实际上在做什么(正如我在即时 Window 中检查过的)如下:
return resolvableService.Value as ISectionService<ISectionView>;
这是个问题,因为我的服务要转换为以下内容:
return resolvableService.Value as ISectionService<SampleSectionView>;
我知道我已将一个 SampleSectionView 对象传递给此解析方法,但基于通用 V 类型参数的转换有点丢失。
那么我怎样才能让转换识别实际的具体类型,而不是创建它的接口类型?
郑重声明,我知道我可以做到以下几点:
var sectionType = new SampleSectionView();
但这是一个问题,因为我需要一个工厂方法来创建 ISectionView,所以我知道这是我传递给 Resolve 的类型。是的,我明白为什么这是一个问题,那么可以做些什么来克服这个问题呢?如果可能的话,我宁愿 而不是 有一个 switch/case 语句来处理转换。
谢谢
回答
感谢所有评论。最后,我所要做的就是将 ISectionService 接口修改为以下内容:
public interface ISectionService<out T> where T : ISectionView { }
这就足够了。
接口不能以这种方式工作,让接口 IInterface<IBase>
转换为 IInterface<IDerived>
的唯一方法是使用 out
参数声明接口。
我建议阅读此 question 中的答案。我相信它会为您提供所需的信息。
我不确定这是最好的解决方案,但您可以将其包装到 non-generic 带反射的方法中。
class ServiceResolver
{
public ISectionService<ISectionView> ResolveNonGeneric(ISectionView sectionViewModel)
{
var method = GetType()
.GetMethod(nameof(Resolve), BindingFlags.Public | BindingFlags.Instance)
.MakeGenericMethod(sectionViewModel.GetType());
return (ISectionService<ISectionView>) method.Invoke(this, new[] { sectionViewModel });
}
public ISectionService<V> Resolve<V>(V sectionViewModel) where V : ISectionView
{
//V is SampleSectionView
}
}
从而执行:
ISectionView sectionType = new SampleSectionView();
var service = _serviceResolver.ResolveNonGeneric(sectionType);
将在内部执行Resolve<SampleSectionView>
。
虽然这需要使 ISectionService<T>
协变。