0

列挙型が与えられた場合:

public enum Work
{
    Normal,
    Extended
}

私がやりたいのは次のとおりです。

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>
{
}

特に、Builderでスイッチ/ケースを使用したり、Workに新しい列挙値を追加するときに維持する必要があるマッピングを使用したりすることは避けたいです。つまり、これを行うことができます。

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 ...
        }
    }
}

したがって、基本的には、列挙値に応じてクラスのインスタンスを作成する必要があり、クラスは抽象クラスの子クラスである必要があります。

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 に答える