错误:“类型不能用作泛型类型的方法中的类型参数。”这可以通过约束或铸造来解决吗?

时间:2014-02-08 20:23:48

标签: c# generics types

我在与工厂进行实验时遇到了编译错误。这不是我会使用的实际工厂实现,因为我可能会在实际代码中使用DI系统。我想提前说明这一点,因为那不是我正在寻求帮助的。

令我困惑的是下面的代码片段是如何约束Create()方法以便可以返回多个类型。编译器错误是:

The type 'TConcreteType' cannot be used as type parameter 'TConcreteType'
in the generic type or method 'Tests.IFactory<TFactoryType>.Create<TConcreteType>(int)'.
There is no boxing conversion or type parameter conversion from 'TConcreteType' to 
'Tests.IFoo'.

以下是示例代码的重要部分:

public static class UniversalFactory
{
    // New factories should be added here.
    private static readonly IFactory<IFoo> FooFactoryEx;
    private static readonly IFactory<IBar> BarFactoryEx;

    static UniversalFactory()
    {
        // These bindings could also be provided via a DI framework like Ninject.
        FooFactoryEx = new FooFactory();
        BarFactoryEx = new BarFactory();
    }

    // Maps concrete objects to factories according to the interface(s) they implement.
    public static TConcreteType Create<TConcreteType>(int id)
    {
        if (typeof(TConcreteType).IsAssignableFrom(typeof(IFoo)))
            return FooFactoryEx.Create<TConcreteType>(id);
        if (typeof(TConcreteType).IsAssignableFrom(typeof(IBar)))
            return BarFactoryEx.Create<TConcreteType>(id);
        return default(TConcreteType);
    }
}

上述测试代码如下:

public class TestClass
{
    public void TestMain()
    {
        var foo1 = UniversalFactory.Create<FooImpl>(1);
        var foo2 = UniversalFactory.Create<FooImpl>(2);
        var bar1 = UniversalFactory.Create<BarImpl>(1);
    }
}

错误似乎是必须将TConcreteType约束为此行的IFoo:

return FooFactoryEx.Create<TConcreteType>(id);

同时(不可能)约束IBar这条线:

return BarFactoryEx.Create<TConcreteType>(id);

但是我希望这个没有约束,因为我可以进行类型检查,例如:

if (typeof(TConcreteType).IsAssignableFrom(typeof(IFoo)))

但是,没有任何约束或类型转换解决了这种情况。我是否尝试做一些不可能的事情,或者是否存在我尚未尝试的编译器错误所隐含的明显约束?

编辑#1:我应该指出“FooImpl:IFoo”和“BarImpl:IBar”。

编辑#2:此信息是为Chris Martin添加的,因为我在我的示例中遗漏了一个关键的类型约束:

public interface IFactory<in TFactoryType>
{
    TConcreteType Create<TConcreteType>(int id) where TConcreteType : TFactoryType;
}

3 个答案:

答案 0 :(得分:2)

如果您无法理解此错误的来源,您应该尝试执行编译器所做的操作 - 将泛型替换为实际类型。以下是TConcreteTypeFooImpl时的情况:

public static FooImpl Create(int id)
{
    if (typeof(FooImpl).IsAssignableFrom(typeof(IFoo)))
    //"where FooImpl : IFoo", returns FooImpl, looks fine
        return FooFactoryEx.Create<FooImpl>(id);
    if (typeof(FooImpl).IsAssignableFrom(typeof(IBar)))
    //"where FooImpl : IBar". Wait... what?
        return BarFactoryEx.Create<FooImpl>(id);
    return default(FooImpl);
}

没有多大意义,是吗?编译器无法知道BarFactoryEx.Create<FooImpl>(id);从未执行过。除非您愿意从IFactory.Create<T>()中删除类型约束或潜入动态代码生成:),否则无法绕过它。总的来说,我认为你原来的方法更好(UniversalFactory.FooFactory.Create()

答案 1 :(得分:1)

不确定问题。这很好用。

https://gist.github.com/trbngr/8911315

答案 2 :(得分:0)

据我所知,typeof完全返回一些不同的数据类型,只是告诉了什么类是什么。两个typeof应该具有相同的数据类型,即使它们要求两个完全不相关的类的类型。

我认为你需要做的就是让TConcreteType实现IFoo和IBar接口。