接口成员上的C#条件属性
我试图通过使用条件属性来摆脱代码中的“#if TRACE”指令,但无法将此方法轻松应用于接口。我有办法解决这个问题,但这很难看,我正在寻找更好的解决办法 例如,我有一个带有条件编译方法的接口接口成员上的C#条件属性,c#,conditional-attribute,C#,Conditional Attribute,我试图通过使用条件属性来摆脱代码中的“#if TRACE”指令,但无法将此方法轻松应用于接口。我有办法解决这个问题,但这很难看,我正在寻找更好的解决办法 例如,我有一个带有条件编译方法的接口 interface IFoo { #if TRACE void DoIt(); #endif } 我无法在接口中使用条件属性: // Won't compile. interface IFoo { [Conditional("TRACE")] void DoIt(); } 我可以
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.");
}
}
这将使我的客户端代码在非跟踪构建中对'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();
}
}
有更好的方法吗?这个怎么样:
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
}
我建议你改用这个。我将条件语句视为一种代码味道,因为它们隐藏了真正的抽象。是的,您将得到一些额外的方法调用,但这些调用实际上对性能没有影响。在跟踪构建中,您可以通过配置文件注入TraceFoo。这也将使您能够在非跟踪构建上启用它
interface IFoo
{
void DoIt();
}
class NullFoo : IFoo
{
public void DoIt()
{
// do nothing
}
}
class TraceFoo : IFoo
{
public void DoIt()
{
Console.WriteLine("Did it.");
}
}
跟踪方法不应该出现在接口上,因为它是一个实现细节 但是如果你被界面卡住了,无法更改它,那么我会使用
#如果#endif
您开始使用的方法
不过,这是一种相当野蛮的语法,因此我同意您可能希望避免它的原因…您应该将任务留给优化器(或JIT编译器)并使用:
优化器和JIT编译器都不会删除调用,您应该向这些开发人员发送愤怒的电子邮件;) 我喜欢扩展方法。至少对于呼叫者来说,它可以变得更好/更健壮:
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
}
}
公共接口IFoo
{
///
///不要直接调用它,使用IFooExt中的DoIt
///
[过时]
void DoItInternal();
}
公共静态类IFooExt
{
[有条件的(“跟踪”)]
公共静态void DoIt(这个T),其中T:IFoo
{
#pragma警告禁用612
t、 DoItInternal();
#pragma警告恢复612
}
}
公共类SomeFoo:IFoo
{
void IFoo.DoItInternal(){}
公开无效的废话
{
这是DoIt();
this.DoItInternal();//错误
}
}
泛型类型约束用于避免虚拟调用和可能的值类型装箱:优化器应该很好地处理这个问题。至少在VisualStudio中,如果因为过时而调用内部版本,它会生成警告。显式接口实现用于防止意外调用具体类型上的内部方法:使用[Observe]标记它们也有效
虽然这可能不是跟踪内容的最佳方法,但在某些情况下,这种模式是有用的(我是从一个不相关的用例中找到的)。在这里使用对您有用吗?我觉得如果您试图对接口这样做,您可能会在某个地方有一个泄漏的抽象。跟踪信息可能更像是一个实现细节,而不是一个合同细节。@ROMANARMY:是的,这是一个非常糟糕的界面。我只是试着一步一步地清理它。跟踪方法不应该出现在接口上,因为它是一个实现细节。但如果你坚持下去,我会用#如果#您开始使用的endif方法。@Xcaliburp。是的,我想我会坚持使用#if's,直到我从界面上完全删除了与跟踪相关的内容。(如果你在回复中发布,我会接受。)但现在他必须将所有对IFoo的引用更改为FooBase,以便使用他的条件方法……我猜OP中的IFoo实际上有一些行为,而不是DoIt方法,他希望保留在接口上。在这种情况下,传递一个“Null对象”而不是具体的类将丢失一些他想要保留的行为。
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
}
}