【问题标题】:Casting to a generic interface with a dynamic type parameter使用动态类型参数转换为泛型接口
【发布时间】:2014-10-24 14:53:53
【问题描述】:

我有两个这样的通用接口:

public interface IFoo<T> { }
public interface IBar<TFoo, T> where TFoo : Foo<T> { 
    T Qux(TFoo foo);
}

IFoo&lt;T&gt; 有一堆实现,每个都有一个匹配的实现 IBar&lt;S,T&gt;,注册在我的 IoC 容器(恰好是 Castle.Windsor)中。

现在,我想创建一个方法,该方法基于实现IFoo&lt;T&gt; 的某种类型的参数,从Windsor 返回相应的IBar&lt;IFoo&lt;T&gt;,T&gt;。一个简单的实现如下所示:

public IBar<TFoo,T> GetBarFor(IFoo<T> foo) where TFoo : IFoo<T>
{
    return container.Resolve<IBar<TFoo,T>>();
}

但是,在调用代码中,我没有具体输入 Foo&lt;T&gt; - 只是一个 IFoo&lt;T&gt;

public T DoStuffWithStuff<T>(IFoo<T> foo)
{
    var bar = GetBarFor(foo);
    return bar.Qux(foo);
}

并且在这个调用中,编译器无法推断出类型参数(具体来说,我猜是TFoo),所以我需要采取另一种方法。

我尝试使用Resolve() 的非泛型版本解析类型,但无法正确获取返回类型:

public AbstractBar<T> GetBarFor(IFoo<T> foo) where TFoo : IFoo<T>
{
    var barType = typeof(IBar<,>).MakeGenericType(foo.GetType(),typeof(T));
    var bar = container.Resolve(barType); // bar is now a System.Object

    var wrapperType = typeof(BarWrapper<,>).MakeGenericType(foo.GetType(), typeof(T));
    var wrapper = Activator.CreateInstance(wrapperType, bar);

    return (AbstractBar<T>)wrapper;
}

public abstract class AbstractBar<T> { public abstract T Qux(IFoo<T> foo); }

public class BarWrapper<TFoo, T> : AbstractBar<T> where TFoo : IFoo<T>
{
    private IBar<TFoo,T> _inner;
    public BarWrapper(IBar<TFoo,T> inner) { _inner = inner; }

    public T Qux(IFoo<T> foo) { return _inner.Qux((TFoo)foo); }
}

但我在Activator.CreateInstance 调用中不断收到异常,说找不到BarWrapper 的构造函数(是的,一切都是public)。

有没有一种好方法可以让上述DoStuffWithStuff 中的调用完全适用于该签名(即我不能从调用代码中推迟任何更具体的泛型)?


脚注:我在Jimmie Bogard's MediatR implementation of the mediator pattern 中看到了后一种模式的工作原理,实际上我在这里尝试完成的是一个非常相似的实现,它不依赖于公共服务定位器,但是而是直接进入我们的 IoC 容器。在上下文中,IFoo&lt;T&gt; 真的是IRequest&lt;out TResponse&gt;IBar&lt;TFoo, T&gt; 真的是IRequestHandler&lt;in TRequest, out TResponse&gt;,等等。

查看他的代码,并尝试重新创建它,但通过调用 Windsor 容器而不是服务定位器,我无法弄清楚为什么他的代码有效,而我的却没有。

【问题讨论】:

  • 旁注:与其说“是的,一切都是公开的”,不如显示正确的代码,例如public BarWrapper(...
  • 类 BarWrapper { BarWrapper(); ... } 你确定构造函数是公开的吗?
  • 您是否尝试过让GetBarFor 的非反射版本首先工作? (指定类型而不是 foo.GetType() 并让它编译/运行)
  • @AlexeiLevenkov 和 Igor:我试图为自己节省一些打字时间,但我知道为什么这会令人困惑。我更新了代码示例以反映实际代码。
  • @AlexeiLevenkov:是的,我试过了,并且让它工作了,但不幸的是,它要求我一直提供类型参数,直到调用 DoStuffWithStuff,这是我无法拥有的(它会打败将 IoC 容器注入我的调解器的目的......)。我还没有找到一种方法来让它工作,它既不需要 a) 在最外层调用中需要类型参数,也不需要 b) 使用反射。

标签: c# generics reflection type-inference


【解决方案1】:

未经测试,但您需要使用反射将类型后期绑定到您要执行的泛型的方法信息。

      var wrapperType = typeof(BarWrapper<,>).MakeGenericType(foo.GetType(), typeof(T));

      MethodInfo TempMethodInfo = typeof(MYClass).GetMethod("DoStuffWithStuff")         

      MethodInfo GenericParam = TempMethodinfo.MakeGenericMethod(T);

      var Formatter = Delegate.CreateDelegate(wrapperType , GenericParam);

【讨论】:

    【解决方案2】:

    您可以使用旧的 dynamic 关键字。

    基本上它允许运行时找出正确的类型。

    IBar<TFoo,T> GetBarFor<TFoo, T>(TFoo dummy, IFoo<T> secondDummy) 
        where TFoo : IFoo<T>
    {
        return container.Resolve<IBar<TFoo, T>>();
    }
    

    以及GetBarFor的用法:

    GetBarFor((dynamic)foo, (dynamic)foo);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多