将泛型类强制转换为接口

本文关键字:接口 转换 泛型类 | 更新日期: 2023-09-27 18:07:44

我有一个问题,将泛型类强制转换为它正在实现的接口。

我的代码是这样的:
interface foo
{
    void foobar();
}
class bar: foo
{
    public void foobar()
    {
        throw new NotImplementedException();
    }
}

现在我有了通过接口创建类实例的工厂,主要是一个简单的微内核(服务定位器)。我在这里化简一下。通常情况下,它将从配置和工厂中查找实现类,并将类型作为T,但这对于我遇到的问题无关紧要。

public static class Factory
{

    public static Lazy<foo> CreateLazyInstance()
    {
        Lazy<foo> instance;

        Type type = typeof(bar);
        Type lazyType = typeof(Lazy<>);
        Type toContruct = lazyType.MakeGenericType(type);
        instance = (Lazy<foo>)Activator.CreateInstance(toContruct);
        return instance;
    }
}

If将在:

instance = (Lazy<foo>)Activator.CreateInstance(toContruct);

并使用InvalidCastException声明不可能将类型Lazy<bar>转换为Lazy<foo>

是否有办法告诉CLR这个强制转换将工作或解决这个问题?

将泛型类强制转换为接口

No - Lazy<T>不变的 -所以Lazy<string>不是Lazy<object>。(正如在评论中指出的,它不能在T中被声明为协变,因为它是一个类,而不是接口或委托。)

但是,您可以很容易地将其中一种转换为另一种:

static Lazy<TOutput> CreateLazyProxy<TInput, TOutput>
    (Lazy<TInput> input) where TInput : TOutput
{
    return new Lazy<TOutput>(() => input.Value);
}

同样,Func<T> 协变的,所以这也可以工作:

static Lazy<TOutput> CreateLazy<TInput, TOutput>(Func<TInput> func)
    where TInput : TOutput
{
    return new Lazy<TOutput>(func);
}

(并不是说你特别需要一个方法——如果你已经得到了一个Func<TInput>,直接构造一个Lazy<TOutput>就可以了)

更简单的方法是将lambda传递给Lazy构造函数。因此,您的代码看起来像下面这样:

  public static Lazy<foo> CreateLazyInstance()
  {
     Type type = typeof(bar);
     return new Lazy<foo>(() => (foo)Activator.CreateInstance(type));
  }  

您必须执行您的foo泛型参数:new():

public static Lazy<foo> CreateLazyInstance() where foo : new()

并更改代码以找到一个构造函数并调用它:

Type t = typeof(foo);
t.GetConstructor(new type[]{});
return (foo)t.Invoke(new object[]{});