服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#8.0默认接口实现的详细实例

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

2022-11-20 15:52WeihanLi C#

Microsoft使用C#8.0发布了许多新功能,他们引入的主要功能之一是默认接口方法。这篇文章主要给大家介绍了关于C#8.0默认接口实现的相关资料,需要的朋友可以参考下

Intro

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

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

Sample

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

?
1
2
3
4
5
6
7
8
9
10
11
12
internal interface IFly
{
    string Name { get; }
}
internal class Superman : IFly
{
    public string Name => nameof(Superman);
}
internal class MonkeyKing : IFly
{
    public string Name => nameof(MonkeyKing);
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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 方法,并提供了一个默认实现,在其中一个实现中进行了重写,我们来写一段代码测试一下吧

?
1
2
3
4
5
6
7
8
// 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 实现,如上面所示。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
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

  • https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/default-interface-methods-versions
  • https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#default-interface-methods
  • https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp9Sample/DefaultInterfaceImplement.cs

总结

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

原文链接:https://mp.weixin.qq.com/s/UgwIZMlRUjvuyoVQRDxC0w

延伸 · 阅读

精彩推荐
  • C#C#实现在listview中插入图片实例代码

    C#实现在listview中插入图片实例代码

    这篇文章主要介绍了C#实现在listview中插入图片实例代码的相关资料,需要的朋友可以参考下...

    net小伙7292021-12-29
  • C#Unity 实现给物体动态添加事件

    Unity 实现给物体动态添加事件

    这篇文章主要介绍了Unity 实现给物体动态添加事件的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    龙虾冖11062022-11-11
  • C#C#中word导出功能的骚操作详解

    C#中word导出功能的骚操作详解

    这篇文章主要给大家介绍了关于C#中word导出功能骚操作的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    随风去远方3872022-11-01
  • C#c# DevExpress gridcontrol日期行的显示格式设置

    c# DevExpress gridcontrol日期行的显示格式设置

    这篇文章主要介绍了c# DevExpress gridcontrol日期行的显示格式设置,需要的朋友可以参考下...

    C#教程网7072021-12-24
  • C#C#利用ZXing.Net生成条形码和二维码

    C#利用ZXing.Net生成条形码和二维码

    这篇文章主要为大家详细介绍了C#利用ZXing.Net生成条形码和二维码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Alan.hsiang6162022-02-21
  • C#C#中如何为枚举类型添加描述方法【小技巧】

    C#中如何为枚举类型添加描述方法【小技巧】

    相信很多人对枚举并不陌生,枚举可以很方便和直观的管理一组特定值。下面这篇文章主要给大家介绍了关于C#中如何为枚举类型添加描述方法的相关资料...

    LamondLu7932022-03-09
  • C#C# FTP操作类分享

    C# FTP操作类分享

    这篇文章主要为大家分享了C# FTP操作类的相关代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    孤者自清4482022-01-11
  • C#C#实现rabbitmq 延迟队列功能实例代码

    C#实现rabbitmq 延迟队列功能实例代码

    本篇文章主要介绍了C#实现rabbitmq 延迟队列功能实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。...

    ThisIsTest8852021-12-31