文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C#8.0默认接口实现的详细实例

2024-04-02 19:55

关注

Intro

C# 8.0 开始引入了默认接口实现,也就是可以在接口里写方法实现。

在之前的版本中接口上是没有办法定义实现的,方法也都是 public 的,除了接口和属性之外是不能定义其他数据的,这也意味着,接口从一开始就要设计得比较好,否则在已有接口里增加新方法的时候其实现就必须要修改,否则就会编译失败,默认接口实现使得可以不造成破坏性变更的前提下在接口中新增加方法,只需要在接口中提供一个默认的实现即可。

Sample

下面我们来看一个示例吧:


internal interface IFly
{
    string Name { get; }
}
internal class Superman : IFly
{
    public string Name => nameof(Superman);
}
internal class MonkeyKing : IFly
{
    public string Name => nameof(MonkeyKing);
}

这是一个基本的接口定义,并提供了两个实现,紧接着我们来为接口新增一个方法,


internal interface IFly
{
    string Name { get; }

    void Fly() => Console.WriteLine($"{Name.GetValueOrDefault((DefaultName))} is flying");
}

internal class Superman : IFly
{
    public string Name => nameof(Superman);

    public void Test()
    {
        ((IFly) this).Fly();
        Console.WriteLine(Name);
    }
}

internal class MonkeyKing : IFly
{
    public string Name => nameof(MonkeyKing);

    public void Fly()
    {
        Console.WriteLine($"I'm {Name}, I'm flying");
    }
}

我们在接口里增加了一个 Fly 方法,并提供了一个默认实现,在其中一个实现中进行了重写,我们来写一段代码测试一下吧


// Cannot resolve symbol 'Fly'
// new Superman().Fly();

IFly fly = new Superman();
fly.Fly();

fly = new MonkeyKing();
fly.Fly();

输出结果如下:

Superman is flying
I'm MonkeyKing, I'm flying
IFly

上面的示例中 Superman 没有定义 Fly 这个方法,是不能直接调用 Fly 方法的,需要先转成 IFly 接口然后再调用,此时方法实现是在接口里定义的逻辑,而 MonkeyKing 实现了 Fly 方法,所以会使用它自己的 Fly 实现,如上面所示。

除了上面的基本用法之外,现在可以在接口里定义静态字段静态方法来实现更好的方法复用,我们在上面的示例里演示一下,修改后的示例如下:


internal interface IFly
{
    private const string DefaultName = nameof(IFly);

    protected static string GetDefaultName() => DefaultName;

    public static string GetPublicName() => DefaultName;

    // Interface cannot contain instance fields
    // private string name = "";

    string Name { get; }

    void Fly() => Console.WriteLine($"{Name.GetValueOrDefault((DefaultName))} is flying");
}

internal class MonkeyKing : IFly
{
    public string Name => nameof(MonkeyKing);

    public void Fly()
    {
        Console.WriteLine($"I'm {Name}, I'm flying, DefaultName:{IFly.GetDefaultName()}");
    }
}

如果定义了 protected static 的方法或字段,则在实现接口的类中就可以通过 IFly.GetDefaultName() 来调用接口中的方法了,如果是 protected 就只能在实现它的类型中使用,如果要在没有实现接口的类型中调用可以声明为 public 就可以了,下面是在没有实现接口的类型中调用的示例:

// Cannot access protected method 'GetDefaultName' here
// IFly.GetDefaultName().Dump();

IFly.GetPublicName().Dump();

More

虽然现在可以这样用,但我个人还是推荐沿用之前的接口用法,不要轻易使用这个特性,提前设计提前规划才是正道,不要想着事后补偿,感觉这个特性比较合适的一个使用场景是现在基于接口的扩展方法,扩展方法作为一个接口的默认实现,具体类可以重写这个实现,使用示例如下:


Task<bool> SaveProperties(int id, Dictionary<string, object> properties)
{
    if (properties is null || properties.Count == 0) return Task.FromResult(false);
    var json = JsonConvert.SerializeObject(properties.Select(p => new PropertyModel()
    {
        PropertyName = p.Key,
        PropertyValue = p.Value?.ToString()
    }));
    return SaveProperties(id, json);
}

Task<bool> SaveProperties(int id, string properties);

在之前的版本中,我一般都是把上面的方法作为一个扩展方法来用,有个默认接口实现之后也可以考虑加一个默认实现(仅限于业务代码中,针对类库代码,感觉还是越干净越好)

References

总结

到此这篇关于C#8.0默认接口实现的文章就介绍到这了,更多相关C#8.0默认接口内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯