我在与工厂进行实验时遇到了编译错误。这不是我会使用的实际工厂实现,因为我可能会在实际代码中使用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;
}
答案 0 :(得分:2)
如果您无法理解此错误的来源,您应该尝试执行编译器所做的操作 - 将泛型替换为实际类型。以下是TConcreteType
为FooImpl
时的情况:
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)
不确定问题。这很好用。
答案 2 :(得分:0)
据我所知,typeof完全返回一些不同的数据类型,只是告诉了什么类是什么。两个typeof应该具有相同的数据类型,即使它们要求两个完全不相关的类的类型。
我认为你需要做的就是让TConcreteType实现IFoo和IBar接口。