1

switch ステートメントの return の変換が .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
    {
    }
}
4

2 に答える 2

3

これStandardProductProcessorは、 が type のオブジェクトを期待しているためですStandardProduct

設計時には、Product.

everyStandardProductは ですがProduct、その逆にはなりません。すべてProductが であるとは限りません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 に答える