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

网友投稿 208 2024-02-03


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

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($"Im {Name}, Im flying"); } }

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

// Cannot resolve symbol Fly // new Superman().Fly(); IFly fly = new Superman(); fly.Fly(); fly = new MonkeyKing(); fly.Fly();

输出结果如下:

Superman is flying

Im MonkeyKing, Im 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($"Im {Name}, Im 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

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列、每页16列等等)。加载的数组总数量超过设置的每页列数后,需分页展示。可以直接点击指定的列数或者上 ...


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:接口规范 13. 文件上传及管理相关接口
下一篇:php 接口隔离原则分析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~