【问题标题】:Default implementation in interface is not seen by the compiler?编译器看不到接口中的默认实现?
【发布时间】:2020-03-15 23:09:49
【问题描述】:

这是我在 c# 项目中的代码,该项目针对 .NET Core 3.0(所以我应该使用 C# 8.0)和 Visual Studio 2019 (16.3.9)

public interface IJsonAble
{
    public string ToJson() => System.Text.Json.JsonSerializer.Serialize(this);
}

public class SumRequest : IJsonAble
{
    public int X { get; set; }

    public int Y { get; set; }

    public void Tmp()
    {
        new SumRequest().ToJson(); //compile error
    }
}

编译错误是:

CS1061“SumRequest”不包含“ToJson”的定义,并且找不到接受“SumRequest”类型的第一个参数的可访问扩展方法“ToJson”(您是否缺少 using 指令或程序集引用?)

有人能解释一下这种行为吗?

【问题讨论】:

  • 即使使用 C# 8.0,该类也不会从接口继承实现。您必须强制转换为接口类型才能使用默认实现。
  • 虽然 C# 8 允许在接口中实现具体的方法 (stackoverflow.com/a/45912519/3759822),但我仍然认为 OOP 方面不是一个好主意,我建议你将 interface IJsonAble 更改为 abtract class AbstractJsonAble。我知道此评论与您的​​问题没有直接关系,记住这一点可能会有所帮助。
  • 遇到了同样的问题,这是心理问题!我的意思是默认 impl 的全部目的。在接口上是我们不再需要在我们自己的接口上添加通用功能作为扩展。如果这应该更接近于任何意义,那么通过对实现类型的引用,既不应该看到常规接口方法,也不应该看到接口的扩展。我真的很想看看这个决定背后的原因。
  • @jool 原因是“它允许您添加到界面而不用担心下游后果”(见接受的答案)

标签: c# c#-8.0 default-interface-member


【解决方案1】:

方法仅在接口上可用,在上不可用。所以你可以这样做:

IJsonAble request = new SumRequest()
var result = request.ToJson();

或者:

((IJsonAble)new SumRequest()).ToJson();

这样做的原因是它允许您添加到接口而不用担心下游后果。例如,ToJson 方法可能已经存在于 SumRequest 类中,您希望调用哪个方法?

【讨论】:

    【解决方案2】:

    尝试使用(new SumRequest() as IJsonAble).ToJson(); 对编译器有所帮助。

    无论如何,假设您想在当前 SumRequest 实例上应用 ToJson,我确定您所追求的是 (this as IJsonAble).ToJson()

    【讨论】:

    • 我不建议在这里使用as。如果对象没有实现IJsonAble,那么你将得到一个空引用异常。如果您确定该类型确实实现了它,请使用硬转换。
    • 鉴于这是 c# 8.0,如果启用 Nullable 引用类型功能,则会在停止实现 IJsonAble 时收到编译器警告。建议使用强制转换,特别是在使用旧版本的 C# 时,但不会改变答案的本质。
    • 注意:在 C# 8.0 中使用硬转换时,它会抑制使用“as”时收到的“取消引用可能的空引用”警告(对于停止实现 IJsonAble 接口的情况) .我更喜欢编译时警告而不是运行时异常。
    猜你喜欢
    • 2020-02-01
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多