8

代わりにConditional属性を使用して、コード内の「#if TRACE」ディレクティブを削除しようとしていますが、このアプローチをインターフェイスに簡単に適用することはできません。私にはこれを回避する方法がありますが、それはかなり醜いです、そして私はより良い解決策を探しています。

たとえば、条件付きでコンパイルされたメソッドとのインターフェースがあります。

interface IFoo
{
#if TRACE
    void DoIt();
#endif
}

インターフェイスで条件属性を使用できません:

// Won't compile.
interface IFoo
{
    [Conditional("TRACE")]
    void DoIt();
}

インターフェイスメソッドに、具象クラスの条件付きプライベートメソッドを呼び出すだけで済みます。

interface IFoo
{
    void TraceOnlyDoIt();
}

class Foo : IFoo
{
    public void TraceOnlyDoIt()
    {
        DoIt();
    }

    [Conditional("TRACE")]
    void DoIt()
    {
        Console.WriteLine("Did it.");
    }
}

これにより、非TRACEビルドで「nop」TraceOnlyDoIt()メソッドへの冗長な呼び出しがクライアントコードに残ります。インターフェイスの条件付き拡張メソッドでそれを回避することはできますが、少し醜いです。

interface IFoo
{
    void TraceOnlyDoIt();
}

class Foo : IFoo
{
    public void TraceOnlyDoIt()
    {
        Console.WriteLine("Did it.");
    }
}

static class FooExtensions
{
    [Conditional("TRACE")]
    public static void DoIt(this IFoo foo)
    {
        foo.TraceOnlyDoIt();
    }
}

これを行うためのより良い方法はありますか?

4

5 に答える 5

7

私は拡張方法のアプローチが好きです。少なくとも発信者にとっては、少し優れた/堅牢なものにすることができます。

    public interface IFoo
    {
        /// <summary>
        /// Don't call this directly, use DoIt from IFooExt
        /// </summary>
        [Obsolete]
        void DoItInternal();
    }

    public static class IFooExt
    {
        [Conditional("TRACE")]
        public static void DoIt<T>(this T t) where T : IFoo
        {
#pragma warning disable 612
            t.DoItInternal();
#pragma warning restore 612
        }
    }

    public class SomeFoo : IFoo
    {
        void IFoo.DoItInternal() { }

        public void Blah()
        {
            this.DoIt();
            this.DoItInternal(); // Error
        }
    }

ジェネリック型の制約は、仮想呼び出しと値型の潜在的なボクシングを回避するために使用されます。オプティマイザーはこれを適切に処理する必要があります。少なくともVisualStudioでは、廃止されたために内部バージョンを呼び出すと警告が生成されます。明示的なインターフェイスの実装は、具象型の内部メソッドを誤って呼び出すことを防ぐために使用されます。[廃止]でそれらをマークすることも機能します。

これはTraceのものにとって最良のアイデアではないかもしれませんが、このパターンが役立つ場合があります(私は、無関係のユースケースからここで自分の道を見つけました)。

于 2016-08-25T05:42:28.693 に答える
5

トレースメソッドは実装の詳細であるため、インターフェイスに表示されるべきではありません。

しかし、もしあなたがインターフェースに固執していて、それを変更できないのなら、私は#if ... #endifあなたが始めたアプローチを使うでしょう。

しかし、それはかなり野蛮な構文なので、なぜあなたがそれを避けたいのかについて私は同情します...

于 2011-03-21T10:43:34.710 に答える
1

これはどうですか:

interface IFoo
{
  // no trace here
}

class FooBase : IFoo
{
#if TRACE
    public abstract void DoIt();
#endif
}

class Foo : FooBase
{
#if TRACE
    public override void DoIt() { /* do something */ }
#endif
}
于 2011-03-09T07:36:50.690 に答える
1

代わりにnullオブジェクトパターンを使用することをお勧めします。条件文は実際の抽象化を隠しているので、一種のコードの臭いと見なします。はい、いくつかの追加のメソッド呼び出しがありますが、これらは実質的にパフォーマンスに影響を与えません。トレースビルドでは、たとえば設定ファイルを介してTraceFooを挿入できます。これにより、非トレースビルドでも有効にできるようになります。

interface IFoo
{
    void DoIt();
}

class NullFoo : IFoo
{
    public void DoIt()
    {
      // do nothing
    }
}

class TraceFoo : IFoo
{
    public void DoIt()
    {
        Console.WriteLine("Did it.");
    }
}
于 2011-03-09T08:02:55.317 に答える
1

タスクはオプティマイザー(またはJITコンパイラー)に任せて、以下を使用する必要があります。

interface IWhatever
{
  void Trace(string strWhatever);
}

class CWhatever : IWhatever
{
    public void Trace(string strWhatever)
    {
#if TRACE
       // Your trace code goes here
#endif
    }
}

オプティマイザーもJITコンパイラーも呼び出しを削除しませんが、それらの開発者に怒った電子メールを書く必要があります;)。

于 2014-08-18T12:20:43.423 に答える