如何在没有显式转换的情况下内部调用显式接口实现方法?

55

如果我有

public class AImplementation:IAInterface
{
   void IAInterface.AInterfaceMethod()
   {
   }

   void AnotherMethod()
   {
      ((IAInterface)this).AInterfaceMethod();
   }
}

如何在不显式转换的情况下从 AnotherMethod() 调用 AInterfaceMethod()


3
演职人员有什么问题? - adrianm
1
当我发现这个语言特性时,我只是皱了皱眉头。不过,在实现一些接口(如ICloneable)时,它非常有用。 - Jader Dias
3
那为什么不反过来呢?将代码从显式接口方法移动到一个“普通”的方法中,然后让所有方法(包括显式接口方法)都调用该方法。 - adrianm
在我看来,@adrianm上面的评论是这里最好的答案![当你遇到这种情况或者你预计会需要这个时,这也是一个很好的重构方法。] - ToolmakerSteve
就我所知,在几乎所有情况下,一个“变通方法”是将该方法更改为隐式实现,以允许内部访问同时满足接口合同。缺点是通过声明成员public(并从声明中删除显式的IAInterface.),这使其比您想要的更广泛可见。因此,我不建议这样做,只是提到这是一种可能的替代解决方案。 - ToolmakerSteve
转换比较快;因此,问题中的代码比“as”运算符要快。 - Koray
8个回答

88

不使用转换运算符也有很多方法。

技巧 #1:使用“as”运算符代替转换运算符。

void AnotherMethod()   
{      
    (this as IAInterface).AInterfaceMethod();  // no cast here
}

技巧 #2:通过使用本地变量进行隐式转换。

void AnotherMethod()   
{      
    IAInterface ia = this;
    ia.AInterfaceMethod();  // no cast here either
}

技巧 #3:编写扩展方法:

static class Extensions
{
    public static void DoIt(this IAInterface ia)
    {
        ia.AInterfaceMethod(); // no cast here!
    }
}
...
void AnotherMethod()   
{      
    this.DoIt();  // no cast here either!
}

技巧 #4:引入一个辅助函数:

private IAInterface AsIA => this;
void AnotherMethod()   
{      
    this.AsIA.IAInterfaceMethod();  // no casts here!
}

15
严谨点说,他没有要求不使用“强制类型转换运算符”,而是要求“不用显式强制类型转换”,一般来说,操作符as被认为是“显式强制类型转换”(我不知道这是否符合语言规范定义,或者这个问题在那种情况下是否毫无意义)。 - Pavel Minaev
2
转换操作符和as操作符的语义是非常不同的,因此将它们混淆在一起是一个逻辑错误。有关详细信息,请参见http://beta.blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx。 - Eric Lippert
10
我知道这已经很旧了,但今天我偶然看到了这个问题。我认为“最佳”方法是使用隐式转换,这为代码提供了最好的编译时保护,是吗?如果我使用强制转换或者 "as" 操作(实际上在这种情况下没有意义,因为对象本来就应该实现接口),那么我就有试图将其强制转换为无效接口的风险,从而导致运行时错误。如果我尝试将类隐式转换为它不实现的接口,则会在编译时出现错误,这要好得多。 - julealgon
2
@julealgon:你提出了一个有说服力的观点。 - Eric Lippert
7
如果类A的作者打算允许派生类调用和/或覆盖基类实现,则类A的作者应该创建一个受保护的虚拟方法,而不是一个显式的接口方法。如果类A的作者没有这样的意图,而类B的作者希望类A的作者这样做,则类B的作者应该(1)找到另一个类来扩展,例如编写自己的类,或(2)与类A的作者协商。继承必须是类的一个内置特性。 - Eric Lippert
显示剩余4条评论

10
你可以引入一个辅助的私有属性:
private IAInterface IAInterface => this;

void IAInterface.AInterfaceMethod()
{
}

void AnotherMethod()
{
   IAInterface.AInterfaceMethod();
}

6

我试过这个方法,它有效...

public class AImplementation : IAInterface
{
    IAInterface IAInterface;

    public AImplementation() {
        IAInterface = (IAInterface)this;
    }

    void IAInterface.AInterfaceMethod()
    {
    }

    void AnotherMethod()
    {
       IAInterface.AInterfaceMethod();
    }
}

2
您不必显式将其转换为IAInterface。 - Lukáš Kmoch

2

另一种方法(这是Eric技巧#2的一个衍生版本,如果接口未实现,也应该在编译时出错)

     IAInterface AsIAInterface
     {
        get { return this; }
     }

我认为这比Eric的技术#2更好——如果您预计需要在接口中的多个方法中访问其他接口方法引用。 - Matthew K. Crandall

0

这是不可能的原因,没有显式或隐式转换,因为您可以在同一类中实现更多接口,而所有接口都可以提供相同的方法(相同的名称和签名)。 考虑以下示例:

class MyClass : IAInterface1, IAInterface2
{
   void IAInterface1.DoSomething() { }

   void IAInterface2.DoSomething() { }

   void AnotherMethod
   {
       this.DoSomething(); // ⚡ERROR
       // how should the compiler know which method to link?
   }
}

但是,在我看来,针对您的使用情况,最简单且最优雅(且性能最佳)的解决方案是提供两种方法

  • 一种是实际实现
  • 第二种是显式接口实现,调用第一种方法
class MyClass : IAInterface
{
   void IAInterface.DoSomething() => this.DoSomething();

   private void DoSomething
   {
   }

   void AnotherMethod
   {
       this.DoSomething();
   }
}

-1

你不能这样做,但如果你必须经常这样做,你可以定义一个方便的帮助程序:

private IAInterface that { get { return (IAInterface)this; } }

每当你想调用一个显式实现的接口方法时,你可以使用that.method()代替((IAInterface)this).method()


1
值得注意的是,在这里您不需要显式地进行转换(因为从“this”到实现“IAInterface”的隐式转换)。 - Pavel Minaev

-2

还有一种方法(不是最好的):

(this ?? default(IAInterface)).AInterfaceMethod();

3
考虑到编译器的处理方式,这只是一种繁琐的表达方式,其意思等同于 ((IAInterface)this)。但不利之处在于,如果 thisnull,而且本不应该为 null,它将会在默认实例中调用 AInterfaceMethod,而非抛出异常。几乎肯定不是期望的行为。 - ToolmakerSteve

-4

你不能只是从方法签名中删除 "IAInterface." 吗?

public class AImplementation : IAInterface
{
   public void AInterfaceMethod()
   {
   }

   void AnotherMethod()
   {
      this.AInterfaceMethod();
   }
}

1
那么它就不会是一个显式实现。 - Pavel Minaev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接