1

谁能解释为什么 switch 语句中的 return 转换不能在 .net 4 中编译?我已经更新了示例以更准确地适应我的情况。工厂本身实际上并不通用。

如果我传入一个基本产品(实际上是一个标准产品),即使投射“作为 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
    {
    }
}
4

2 回答 2

3

那是因为StandardProductProcessor期望一个类型为 的对象StandardProduct

在设计时你只知道你有一个Product.

虽然 eachStandardProduct是 a Product,但情况并非相反。不是每个Product都是 a StandardProduct,这就是为什么你需要明确告诉编译器你有一个StandardProduct

于 2013-05-02T18:05:03.993 回答
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
}

标准处理器:

public class StandardProductProcessor : IBaseProductProcessor<StandardProduct> 
{
    public StandardProductProcessor(StandardProduct product)
    {
        Product = product;
    }

    public StandardProduct Product { get; private set; }
}

有了这个,只需修改你的工厂函数如下: public class 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# 中的 out 和 in 关键字),我推荐 Eric Lippert博客中的优秀系列(从底部开始)

于 2013-05-03T12:28:55.953 回答