2
interface IExecutor
{
   void Execute();
}

class Executor2<T> where T : IExecutor
{
    public void Execute()
    {
        var ex = (T)Activator.CreateInstance(typeof(T));
        ex.Execute();
    }
}

インタビューでの質問でした。彼らは、このコードが落ちることがあり(例外を引き起こす)、問題を引き起こす可能性のある少なくとも3つの理由があると私に言いました。どのような例外があったのかは不明です。しかし、このメソッドExecuteは適切に作成されており、その実装に問題はありません。

誰かがそれについて提案がありますか?

編集:問題を引き起こす可能性のある理由は少なくとも3つあります。これらの理由は何ですか?

4

3 に答える 3

4

それに直面して、私はいくつかの問題を見ることができます。

  1. コードはコンパイルされませんが、それを無視してコンパイルさせることができます。
  2. コードはあなたが思っていることをしません。

説明2:T制約付きのクラス定義で型を指定しますが、次に制約なしのメソッドレベルでIExecutor別の型を定義します。Tこれはコンパイルされません。

これを修正<T>してメソッドから定義を削除すると、警告なしに失敗する理由がいくつかわかります。

  1. ex無効である。
  2. タイプTには、パブリックパラメーターなしのコンストラクターが定義されていません。
  3. おそらく、を含むDLLをロードできませんT

ヤクブが見つけたように:

  1. Tインターフェイス(コンストラクターなし)である可能性があります。
  2. T抽象クラスである可能性がありますが、これらはインスタンスを直接作成することを許可しません。

1つ目は、nullチェックを使用しないif (ex != null)ように保護でき、2つ目は、別のジェネリック制約を使用しないように保護できますnew()

class Executor2<T> where T : IExecutor, new()
{
}

もちろん、例外ロギングを含めるようにコードを修正することもできます。これは、暗闇の中で刺すのではなく、実際の問題が何であるかを理解するのに役立つ場合があります。

public void Execute<T>()
{
    try
    {
        var ex = (T)Activator.CreateInstance(typeof(T));
        ex.Execute();
    }
    catch (Exception ex)
    {
        Log(ex); // Mystical logging framework.
        throw;
    }
}

質問がわからなかったので、これが私が一緒に考えられる唯一の答えです。

インタビューでこれを尋ねられた場合、3つすべてに名前を付けることはできなかったと思いますが、コードをより保守しやすくするために変更して、何が問題だったのかを教えてください。それなら私は無意味な面接の質問をするために歩くでしょう。

于 2012-04-13T08:25:27.560 に答える
2

Tインターフェイスまたは抽象クラスの可能性があります。それらのインスタンスを作成できないかT、パラメーターのないコンストラクターがありません。

また、次のvar ex = (T)Activator.CreateInstance(typeof(T));ように書き直すことができますvar ex = Activator.CreateInstance<T>();

于 2012-04-13T08:48:30.090 に答える
2

Tの設計に誤りはないと想定されていますか?つまり、TがBad Stuffを実行する静的コンストラクターを定義している場合、Tの型の初期化は失敗し、パラメーターのないコンストラクターがない場合に発生する例外とは異なる例外が発生します。

さらに言えば、Tが失敗するパラメーターのないコンストラクターを定義している場合、それも壊れています。

また、型にプライベートコンストラクターがある場合は、エラーが発生します。または、タイプがTypeInitialisationExceptionを引き起こすタイプから継承する場合

[編集]

これを試して:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            try { 
                new Executor2<IExecutor>().Execute();
            }
            catch { Console.WriteLine("Failed IExecutor"); }

            try { new Executor2<AbstractExecutorWithImpl>().Execute(); }
            catch { Console.WriteLine("Failed AbstractExecutorWithImpl"); }

            try { new Executor2<AbstractExecutorWithNoImpl>().Execute(); }
            catch { Console.WriteLine("Failed AbstractExecutorWithNoImpl"); }

            try { new Executor2<ConcreteExecutor>().Execute(); }
            catch { Console.WriteLine("Failed ConcreteExecutor"); }

            try { new Executor2<DerivedExecutor>().Execute(); }
            catch { Console.WriteLine("Failed DerivedExecutor"); }

            try { new Executor2<DerivedExecutorWithBadConstr>().Execute(); }
            catch { Console.WriteLine("Failed DerivedExecutorWithBadConstr"); }

            try { new Executor2<DerivedExecutorWithPrivateConstr>().Execute(); }
            catch { Console.WriteLine("Failed DerivedExecutorWithPrivateConstr"); }

            try { new Executor2<DerivedExecutorWithPublicBadConstr>().Execute(); }
            catch { Console.WriteLine("Failed DerivedExecutorWithPublicBadConstr"); }

            Console.ReadLine();
        }
    }


    interface IExecutor
    {
        void Execute();
    }

    abstract class AbstractExecutorWithImpl : IExecutor
    {
        public void Execute()
        {
            Console.Write("Executing AbstractExecutorWithImpl ");
        }
    }
    abstract class AbstractExecutorWithNoImpl : IExecutor
    {
        public abstract void Execute();
    }

    class ConcreteExecutor : IExecutor
    {
        public void Execute()
        {
            Console.WriteLine("Executing ConcreteExecutor");
        }
    }

    class DerivedExecutor : AbstractExecutorWithNoImpl
    {
        public override void Execute()
        {
            Console.WriteLine("Executing DerivedExecutor");
        }
    }

    class DerivedExecutorWithBadConstr : IExecutor
    {
        static DerivedExecutorWithBadConstr() { throw new Exception("Static initialisation Exception"); }
        public void Execute()
        {
            Console.WriteLine("Executing DerivedExecutorWithBadConstr");
        }
    }

    class DerivedExecutorWithPrivateConstr : DerivedExecutor
    {
        private DerivedExecutorWithPrivateConstr() { }
    }
    class DerivedExecutorWithPublicBadConstr : DerivedExecutorWithBadConstr
    {
        public DerivedExecutorWithPublicBadConstr() : base() { }
    }

    class Executor2<T> where T : IExecutor
    {
        public void Execute()
        {
            var ex = (T)Activator.CreateInstance(typeof(T));
            ex.Execute();
        }
    }
}
于 2012-04-13T08:52:25.880 に答える