1

いくつかの操作を調整するパターンを設計しようとしています。各操作はパラメーターを取り、結果を返します。その結果は、次の操作で使用される場合と使用されない場合があります。これはデザインの簡略化されたバージョンですが、これをコンソール プロジェクトにコピー/貼り付けすると「動作」します (修正できないコンパイル エラーがあります)。

エラー

型 'ConsoleApplication1.InternalDebit' は、ジェネリック型またはメソッド 'ConsoleApplication1.Orchestrator.Add(T1)' の型パラメーター 'T1' として使用できません。「ConsoleApplication1.InternalDebit」から「ConsoleApplication1.Operation」への暗黙的な参照変換はありません。c:\projects\BCP\BaseMvc\ConsoleApplication1\ConsoleApplication1\Program.cs 17 13 ConsoleApplication1

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var internalDebit = new InternalDebit<InternalDebitParameter, InterbankCreditParameter>(new InternalDebitParameter() { Id = 1 });

            var orchestrator = new Orchestrator();

            // error here!
            orchestrator.Add(internalDebit);
        }
    }

    public interface IParameter
    {
    }

    public interface IResult
    {
    }

    public interface IReversible
    {
        void Reverse();
    }


    public interface IOperation<T, R>
        where T : class, IParameter
        where R : class, IResult
    {
        Type ParameterType { get; }

        Type ResultType { get; }

        T Parameter { get; set; }

        R Execute(T parameter);
    }

    public abstract class Operation<T, R> : IOperation<T, R>
        where T : class, IParameter
        where R : class, IResult
    {
        public virtual R Execute(T parameter)
        {
            this.Parameter = parameter;
            return default(R);
        }

        public Type ParameterType
        {
            get { return typeof(T); }
        }

        public Type ResultType
        {
            get { return typeof(R); }
        }

        public T Parameter { get; set; }

        public Operation(T parameter)
        {
            this.Parameter = parameter;
        }
    }

    public class InternalDebitParameter : IParameter
    {
        public int Id { get; set; }
    }

    public class InterbankCreditParameter : IParameter, IResult
    {
        public int Id { get; set; }
    }



    public class InternalDebit<T, R> : Operation<T, R>
        where T : class, IParameter
        where R : class, IResult
    {
        public InternalDebit(T parameter)
            : base(parameter)
        {
        }

        public override R Execute(T parameter)
        {
            return new InterbankCreditParameter() { Id = 2 } as R;
        }
    }

    public class Orchestrator
    {
        public List<Operation<IParameter, IResult>> Operations { get; private set; }

        public List<IParameter> Parameters { get; private set; }

        public void Add<T1>(T1 t) where T1 : Operation<IParameter, IResult>
        {
            this.Operations.Add(t);
        }

        public void SetUpParameters(params IParameter[] parameters)
        {
            this.Parameters = new List<IParameter>();

            parameters.ToList().ForEach(s => this.Parameters.Add(s));
        }

        public void Play()
        {
            IParameter generalResult = null;

            foreach (var instrument in this.Operations)
            {
                var parameter = this.Parameters.FirstOrDefault(s => s.GetType() == instrument.ParameterType);

                if (parameter == null)
                {
                    IResult actualResult = null;

                    if (generalResult != null)
                    {
                        try
                        {
                            actualResult = instrument.Execute(generalResult);
                        }
                        catch (Exception ex)
                        {
                            if (instrument is IReversible)
                                ((IReversible)instrument).Reverse();
                            else
                                throw;
                            break;
                        }
                        finally
                        {
                            if (actualResult is IParameter)
                                generalResult = (IParameter)actualResult;
                        }
                    }
                    else
                    {
                        throw new Exception("Orchetrator missconfiguration.");
                    }
                }
            }
        }
    }
}
4

3 に答える 3

1

あなたはジェネリックを C++ のテンプレート化能力に取り込んでいます。エラーが発生する行で、暗黙的に関数を作成しています。

 public void Add(InternalDebit<InternalDebitParameter, InterbankCreditParameter>);

宣言されているように、このクラスは以下から継承します。

 Operation<InternalDebitParameter, InterbankCreditParameter>

ただし、一般的な要件では、 T1 は type であるべきであると述べられてOperation<IParameter, IResult>いますが、ポリモーフィズムが許可されていないため、両方のパラメーターが正しい型から継承されていても、そうではありません。

ここで達成しようとしていることは、ジェネリック (実際には C++ のテンプレート) では本質的に不可能です。ジェネリクスは、ある意味で、ほんの少しのコードで多くのクラスを記述することの贅沢な省略形にすぎないことを覚えておく必要があります。ジェネリックは、再帰的なポリモーフィズムを突然導入するわけではありません。

簡単に言うと、ジェネリックに依存するのではなく、継承と基本クラスを使用するようにコードを書き直します。パターン全体が単一のジェネリックなしで可能であり、タイプセーフであると思われます。

于 2013-04-23T20:54:49.073 に答える