确保一个 C# 方法与接口默认实现的签名匹配

huangapple go评论65阅读模式
英文:

Making sure a C# method matches the signature of an interface default implementation

问题

以下是翻译好的部分:

考虑以下的C#示例:

using System;

interface IExample
{
   public int Foo() => 42;
}

class ExampleImplementation : IExample
{
   public int Foo() => 37;
}

class Program
{
   static void Main(string[] args)
   {
       IExample example = new ExampleImplementation();
       Console.WriteLine($"{example.Foo()}");
   }
}

该代码将会按预期输出37。

然而,如果我在接口中改变方法的签名,但不改变实现的签名,就像这样:

interface IExample
{
   int Foo(int additional_argument) => additional_argument + 42;
}

class ExampleImplementation : IExample
{
   int Foo() => 37;
}

class Program
{
   static void Main(string[] args)
   {
       IExample example = new ExampleImplementation();
       Console.WriteLine($"{example.Foo(0)}");
   }
}

该程序将输出42。

现在这是不希望的行为,因为ExampleImplementation中的Foo方法是写来实现(和覆盖)默认实现的,但在新的代码中它未能做到。

有一些方法可以减轻这个问题,比如使用一个允许您在整个链中更改方法签名的集成开发环境(IDE)。然而,我想知道是否在语言级别有什么可以防止这种情况发生的方法。

另外,值得一提的是,在C++中,override关键字用于确保成员函数实际上是从基类中继承的:以确保成员函数实际上是从基类继承的。如果我使用抽象类,那么我可以做类似的事情,但我想知道是否有类似于默认接口实现的东西。

英文:

Consider the following C# example:

using System;

interface IExample
{
   public int Foo() => 42;
}

class ExampleImplementation : IExample
{
   public int Foo() => 37;
}

class Program
{
   static void Main(string[] args)
   {
       IExample example = new ExampleImplementation();
       Console.WriteLine($"{example.Foo()}");
   }
}

The code will output 37 as expected.

However, if I change the method signature in the interface, but NOT that of the implementation, like this:

interface IExample
{
   int Foo(int additional_argument) => additional_argument + 42;
}

class ExampleImplementation : IExample
{
   int Foo() => 37;
}

class Program
{
   static void Main(string[] args)
   {
       IExample example = new ExampleImplementation();
       Console.WriteLine($"{example.Foo(0)}");
   }
}

The program will output 42 instead.

Now this is undesired behavior, because the method Foo in ExampleImplementation is written to implement (and override) the default implementation, but in the new code it fails to do so.

There are ways to mitigate this, such as using an IDE that allows you to change the signature of methods along the chain. However, I wish to know whether is anything at the language level that can prevent this.

As a side note, in C++, the override keyword is used for exactly this purpose: to make sure a member function is actually overriding something from the base. If I were using an abstract class, then I can do something similar, but I want to know if there is something similar to default interface implementations.

答案1

得分: 2

Explicit 在 C# 中的接口实现要求与它们实现的方法的签名匹配,所以你可以这样做:

class ExampleImplementation : IExample
{
   int IExample.Foo() => 37;
   
   public int Foo() => ((IExample)this).Foo();
}

公共方法被添加以便你仍然可以在类型为 ExampleImplementation 的对象上调用 Foo

或者,你可以这样做,"the other way round":

class ExampleImplementation : IExample
{
   int IExample.Foo() => Foo();
   
   public int Foo() => 37;
}
英文:

Explicit interface implementations in C# are required to match the signatures of the method they are implementing, so you could do:

class ExampleImplementation : IExample
{
   int IExample.Foo() => 37;
   
   public int Foo() => ((IExample)this).Foo();
}

The public method is added so that you can still call Foo on something of type ExampleImplementation.

Alternatively, you can do it "the other way round":

class ExampleImplementation : IExample
{
   int IExample.Foo() => Foo();
   
   public int Foo() => 37;
}

答案2

得分: 0

这可能是显式接口实现的一个用例。如果您将实现编写为:

class ExampleImplementation : IExample
{
   int IExample.Foo() => 37;
}

然后更改IExample中的Foo的签名,上面的代码将不再编译。

但是,这也将使您无法在不先将其转换为IExample的情况下调用ExampleImplementation上的Foo实现。也就是说,这将继续工作:

IExample example = new ExampleImplementation();
Console.WriteLine($"{example.Foo()}");

但这将不会:

ExampleImplementation example = new ExampleImplementation();
Console.WriteLine($"{example.Foo()}");

根据您的具体情况,这可能会成为问题或不成问题。

英文:

This could be a usecase for explicit interface implementation. If you write your implementation as:

class ExampleImplementation : IExample
{
   int IExample.Foo() => 37;
}

And then change the signature of Foo in IExample, the above code will no longer compile.

However, this will also make it impossible to call the Foo implementation on an ExampleImplementation without first casting to IExample. That is, this will still work:

IExample example = new ExampleImplementation();
Console.WriteLine($"{example.Foo(0)}");

But this won't:

ExampleImplementation example = new ExampleImplementation();
Console.WriteLine($"{example.Foo(0)}");

Depending on the particulars of your situation, that may or may not be a problem.

huangapple
  • 本文由 发表于 2023年2月14日 09:02:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75442569.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定