将泛型类转换为接口

时间:2011-09-05 16:16:22

标签: c# generics casting clr

我将通用类转换为它正在实现的接口时遇到问题。

我的代码是这样的:

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;
    }
}

如果失败于:

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

并声明InvalidCastException,无法将类型Lazy<bar>强制转换为Lazy<foo>

有没有办法告诉CLR这个演员会有效还是解决这个问题?

3 个答案:

答案 0 :(得分:5)

否 - 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>。)

答案 1 :(得分:1)

更简单的方法是将lambda传递给Lazy构造函数。因此,您的代码如下所示:

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

答案 2 :(得分:0)

你必须做你的通用参数:new():

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

并更改代码以查找构造函数并调用它:

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