将枚举作为参数从抽象类传递

时间:2013-12-16 14:10:02

标签: c# enums

我有一个抽象的基类TestFactory,它看起来像:

    public abstract class TestFactory
    {
        //static method that can create concrete factories
        public static TestFactory CreateTestFactory(FactoryType factoryType)
        {
            TestFactory factory = null;
            switch (factoryType)
            {
                case FactoryType.Blood:
                    factory = new BloodTestFactory();
                    break;
                case FactoryType.Urine:
                    factory = new UrineTestFactory();
                    break;
                default:
                    break;
            }
            return factory;
        }
        //BloodTestFactory and UrineTestFactory are concrete types 
        //that will need to create their own tests
        //this enum parameter needs to 'switch' between
        //BloodTestType and UrineTestType
        public abstract LabTest CreateTest(Enum e);
    }
    public enum FactoryType
    {
        Blood,Urine
    }

所以这个类创建了一个具体的工厂,如:

    public class BloodTestFactory :TestFactory
    {

        //both BloodTestFactory and UrineTestFactory will create a LabTest object
        //I would like to have a BloodTestType and UrineTestType enum, what do I need 
        //to do to pass a generic Enum as a parameter and then switch on BloodTestType

        public override LabTest CreateTest(Enum e)
        {
            BloodTest bt = null;
            //switch (e)
            //{
            //    default:
            //        break;
            //}
            //creation logic here
        }
    }
    public enum BloodTestType
    {
        H1AC,Glucose
    }

BloodTest本身是一个抽象类,它将根据Enum值返回一个具体的BloodTest对象。为了清楚起见,我想要一个BloodTestType和一个UrineTestType(未显示)枚举。由于CreateTest方法是抽象的,当我想要创建BloodTestTypeBloodTest枚举时,如何确保我可以将UrineTestType传递给我创建UrineTest?

4 个答案:

答案 0 :(得分:4)

我不确定这是否是采用此要求的最佳方法,我会将设计模式讨论留给评论/其他答案。

我不一定会这样做,但是,为了使你的代码有效,我会在TestFactory上为enum引入一个类级通用参数。

public abstract class TestFactory<TTestType>
{
    public abstract LabTest CreateTest(TTestType testType);
}

派生类然后只需指定泛型参数:

public class BloodTestFactory : TestFactory<BloodTestType>
{
    public override LabTest CreateTest(BloodTestType e)
    {
    }
}

请注意,除非您使用Unconstrained Melody之类的内容,否则enum上的泛型类型约束不会得到太多支持。

另请注意,现在这很难引用共享基类,因为您需要关闭泛型参数:

TestFactory baseReference = myBloodTestFactory; // Not possible.

TestFactory<BloodTestType> baseReference = myBloodTestFactory;

就我个人而言,我可能会将这两个工厂分解为没有基础的单独类,或者考虑使用接口。处理您希望作为“常见”方法的特定参数很困难。

答案 1 :(得分:1)

有一种很好的方法可以做到这一点,并产生如下代码:

var client = new LabTestClient();
client.Run<BloodTestFactory,BloodTestType>(BloodTestType.H1AC);
client.Run<BloodTestFactory,BloodTestType>(BloodTestType.Glucose);
// outputs
//   BloodTest: H1AC
//   BloodTest: Glucose

以下是代码的其余部分,希望它非常自我解释如何使用它/扩展它以满足您的需求 - 每种类型的实验室测试都有具体的类。

首先是客户端和抽象类

public class LabTestClient
{        
    public void Run<TFactory, TInput>(TInput input) where TFactory : LabTestFactory, new()
    {
        LabTestFactory factory = new TFactory();;
        LabTest labTest = factory.CreateLabTest();
        labTest.Run(input);
    }

}

public abstract class LabTest
{        
    public abstract void Run<TInput>(TInput input);
}

public abstract class LabTestFactory
{
    public abstract LabTest CreateLabTest();
}

然后具体实现:

public enum BloodTestType{ H1AC,Glucose }

public class BloodTest: LabTest
{        
    public override void Run<TInput>(TInput input) 
    {
        Console.WriteLine("BloodTest: {0}",input);            
    }
}

public class BloodTestFactory : LabTestFactory
{
    public override LabTest CreateLabTest()
    {
        return new BloodTest();
    }
}

public enum UrineTestType{ A,B }

public class UrineTest: LabTest
{        
    public override void Run<TInput>(TInput input) 
    {
        Console.WriteLine("UrineTest: {0}",input);            
    }
}

public class UrineTestFactory : LabTestFactory
{
    public override LabTest CreateLabTest()
    {
        return new UrineTest();
    }
}

一个实例:http://rextester.com/MUV89315

然而,这仍然不理想,因为个别测试仍然没有强制执行他们的输入 - 事实上,当你在测试中做任何复杂的事情时,你会发现你不知道实际的类型是什么TInput除非您将其强制转换为正确的枚举:

public class UrineTest: LabTest
{        
    public override void Run<TInput>(TInput input) 
    {
        var urineTestType = (UrineTestType)input;
        // do something useful.
    }
}

答案 2 :(得分:0)

只需在重写方法中测试类型安全性:

        public override LabTest CreateTest(Enum e)
        {
            BloodTest bt = null;
            if(!e.GetType.Equals(typeof(BloodTestType)))
            {
               // throw type exception of your choice
            }
        }

答案 3 :(得分:0)

只需在您的基类中添加参数检查:

public abstract class TestFactory
{
    //static method that can create concrete factories
    public static TestFactory CreateTestFactory(FactoryType factoryType)
    {
        if (!Enum.IsDefined(typeof(FactoryType), factoryType)
        {
             throw InvalidEnumArgumentException(...);
        }

        TestFactory factory = null;
        switch (factoryType)
        {
            case FactoryType.Blood:
                factory = new BloodTestFactory();
                break;
            case FactoryType.Urine:
                factory = new UrineTestFactory();
                break;
            default:
                break;
        }
        return factory;
    }       
    //...
}