将泛型类转换为接口

5

我遇到了一个问题,无法将泛型类强制转换为其实现的接口。

我的代码如下:

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

如果尝试将类型为Lazy<bar>的项目转换为Lazy<foo>时出现无效转换异常(InvalidCastException),有没有办法让CLR识别这种类型转换或解决这个问题?


1
你的bar类没有实现foo接口。你的代码甚至无法编译。 - Icarus
1
@Icarus:我认为这不相关。他只是想展示他有一个类层次结构,其中bar实现了foo。 - siride
3个回答

6
不行 - 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
它不可能;它不是一个接口。 - SLaks
1
@SLaks:你可以添加一个Lazy<out T>接口,并让当前类实现该接口。 - siride
1
@siride:除了 Lazy<T> 是 BCL 类,不能被修改。 - SLaks
1
@SLaks:哎呀!我至少可以安慰自己,知道Jon Skeet也犯了类似的错误。 - siride

2
更简单的方法是将lambda表达式传递给Lazy构造函数。因此,您的代码将如下所示:
  public static Lazy<foo> CreateLazyInstance()
  {
     Type type = typeof(bar);
     return new Lazy<foo>(() => (foo)Activator.CreateInstance(type));
  }  

1

你必须将你的foo泛型参数设置为:new():

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

并将您的代码更改为查找构造函数并调用它:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接