0

Given an enum type:

public enum Work
{
    Normal,
    Extended
}

What I would like to do is the following.

public abstract class Builder<T>
{
    public static Builder<T> GetBuilder<T> (T work)
    {
        return new Builder<T> ();
    }
}

public class BuilderNormal : Builder<Work.Normal>
{
}

public class BuilderExtended : Builder<Work.Extended>
{
}

I specifically want to avoid using a switch/case in Builder or using a mapping that I would need to maintain when I would add a new enum value to Work, i.e. I could do this

public abstract class Builder
{
    public static Builder GetBuilder (Work work)
    {
        switch (work)
        {
            case Work.Normal:
                return new BuilderNormal ();

            case Work.Extended:
                return new BuilderExtended ();

            default:
                throw new ...
        }
    }
}

So, basically, I want to create an instance of a class depending on an enum value and the class must be a child class of an abstract class.

4

2 回答 2

6

基本上,你不能按照你设计的方式。泛型类型参数始终用于类型,而不是

你当然可以做的是维护一个单一Dictionary<Work, Func<Builder>>的,让你基本上注册工厂。这将避免 switch 语句,但它仍然是您可能忘记添加值的地方。

我会依靠单元测试来避免这个问题——编写一个测试来检查你是否可以Builder为枚举中的每个值创建一个;然后,如果您在未添加映射的情况下向枚举添加值,您的测试将失败。

编辑:另一种选择是向枚举值添加一个属性,以说明哪个构建器类型对应于该值。然后,您需要使用反射提取该类型并以这种方式实例化它。

于 2012-09-28T14:48:13.540 回答
0

你可以做一些毫无意义、疯狂而缓慢的事情,比如

public abstract class Builder
{
    public static TBuilder GetBuilder<TBuilder>() where TBuilder : Builder
    {
        var ctors = typeof(TBuilder).GetConstructors(
            BindingFlags.Instance | 
            BindingFlags.NonPublic | 
            BindingFlags.Public);

        var matchingCtor = ctors.Single(
            ci =>
                {
                    var paramInfo = ci.GetParameters();

                    if (paramInfo.Length != parameters.Length)
                    {
                        return false;
                    }

                    return !paramInfo.Where((t, i) =>
                        t.ParameterType != parameters[i].GetType()).Any();
                });

        return (TBuilder)matchingCtor.Invoke(parameters);
    }
}

这会给你一种静态的通用实例构造函数,所以你可以这样做,

var builderNormal = Builder.GetBuilder<BuilderNormal>();

但是,为什么不直接调用实例构造函数呢?

于 2012-09-28T15:48:06.810 回答