有谁可以解释为什么switch语句中的返回转换不能在.net 4中编译?我已经更新了示例,以便更准确地了解我的情况。工厂本身并不是通用的。
如果我传入基础产品(实际上是StandardProduct),即使是“作为BaseProductProcessor”进行转换也不起作用。现在,如果我明确地将StandardProduct类型传递给工厂,那么它没问题 - 但我所定义的是所有调用方法中的Product类型:|
如何解决这个问题?
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace testing
{
[TestClass]
public class Test
{
[TestMethod]//fails
public void TestFactoryMethodWithBaseTypePassed()
{
Product product = new testing.StandardProduct();
var pp = new testing.ProductProcessorFactory().Create(product);
Assert.IsNotNull(pp);//fails because T coming into create wasn't the derived type
}
[TestMethod]//passes
public void TestFactoryMethodWithExactType()
{
var pp = new testing.ProductProcessorFactory().Create(new testing.StandardProduct());
Assert.IsNotNull(pp);
}
}
public abstract class BaseProductProcessor<T> where T : Product
{
public T Product { get; set; }
public BaseProductProcessor(T product)
{
Product = product;
}
}
public class StandardProductProcessor : BaseProductProcessor<StandardProduct>
{
public StandardProductProcessor(StandardProduct product)
: base(product)
{
}
}
public class ProductProcessorFactory
{
public ProductProcessorFactory()
{
}
public BaseProductProcessor<T> Create<T>(T product) where T : Product
{
switch (product.ProductType)
{
case ProductType.Standard:
var spp = new StandardProductProcessor(product as StandardProduct);
return spp as BaseProductProcessor<T>;//Nulls if T passed with a Product.. how to explicitly say T is a StandardProduct right here in the factory method so it's centralized?
}
return null;// spp as BaseProductProcessor<T>;
}
}
public class Product
{
public ProductType ProductType { get; set; }
}
public enum ProductType
{
Standard,
Special
}
public class StandardProduct : Product
{
}
}
答案 0 :(得分:3)
那是因为StandardProductProcessor
期望类型为StandardProduct
的对象。
在设计时,您只知道自己有Product
。
虽然每个StandardProduct
都是Product
,但不是相反。并非每个Product
都是StandardProduct
,这就是为什么您需要明确告诉编译器您有StandardProduct
答案 1 :(得分:1)
那么,你想在这里实现模板参数的协方差。基类不可能,但可以使用接口。因此,我建议您使用界面替换abstract class BaseProductProcessor<T>
:
public interface IBaseProductProcessor<out T> where T : Product // out marks argument as covariant
{
T Product { get; } // absense of setter is crusial here - otherwise you'll violate type safety
}
StandartProcessor:
public class StandardProductProcessor : IBaseProductProcessor<StandardProduct>
{
public StandardProductProcessor(StandardProduct product)
{
Product = product;
}
public StandardProduct Product { get; private set; }
}
这样,只需修改您的工厂功能如下: 公共类ProductProcessorFactory { public ProductProcessorFactory() { }
public IBaseProductProcessor<T> Create<T>(T product) where T : Product
{
switch (product.ProductType)
{
case ProductType.Standard:
var spp = new StandardProductProcessor(product as StandardProduct);
return spp as IBaseProductProcessor<T>;//no more nulls!
}
return null;
}
}
通过这些修改,您的两个测试都将通过。
如果你想了解更多关于协方差和逆变(关于C#中的关键词),我推荐Eric Lippert的blog中的优秀系列(从底部开始)