接口成员的C#条件属性

Erg*_*wun 8 c# conditional-attribute

我试图通过使用Conditional属性来摆脱我的代码中的"#if TRACE"指令,但是不能轻易地将这种方法应用于接口.我有一个方法,但它很丑,我正在寻找一个更好的解决方案.

例如,我有一个带有条件编译方法的接口.

interface IFoo
{
#if TRACE
    void DoIt();
#endif
}
Run Code Online (Sandbox Code Playgroud)

我不能在接口中使用条件属性:

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

我可以让接口方法在具体类中调用一个条件私有方法:

interface IFoo
{
    void TraceOnlyDoIt();
}

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

    [Conditional("TRACE")]
    void DoIt()
    {
        Console.WriteLine("Did it.");
    }
}
Run Code Online (Sandbox Code Playgroud)

这将使我的客户端代码在非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();
    }
}
Run Code Online (Sandbox Code Playgroud)

有一个更好的方法吗?

Cra*_*igM 6

我喜欢扩展方法方法。它可以做得更好/更健壮,至少对于呼叫者来说:

    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
        }
    }
Run Code Online (Sandbox Code Playgroud)

通用类型约束用于避免值类型的虚拟调用和潜在的装箱:优化器应该很好地处理这个问题。至少在 Visual Studio 中,如果您通过 Obsolete 调用内部版本,它会生成警告。显式接口实现用于防止意外调用具体类型的内部方法:用 [Obsolete] 标记它们也有效。

虽然这对于 Trace 的东西来说可能不是最好的主意,但在某些情况下这种模式很有用(我从一个不相关的用例中找到了我的方法)。


she*_*tie 5

跟踪方法不应出现在接口上,因为它是一个实现细节.

但是如果你坚持使用界面,并且无法改变它,那么我将使用#if ... #endif你开始使用的方法.

这是一个相当野蛮的语法,所以我同情你为什么要避免它......