获取泛型方法的 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> 协变。