找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2199|回复: 7

C# 8.0 默认接口实现

  [复制链接]
  • 打卡等级:即来则安
  • 打卡总天数:29
  • 打卡月天数:1
  • 打卡总奖励:7791
  • 最近打卡:2025-12-13 17:25:16

2540

主题

1355

回帖

2万

积分

管理员

积分
21304
发表于 2021-5-19 20:20:20 | 显示全部楼层 |阅读模式
C# 8.0 默认接口实现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
  • 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



阅读 1029




工控课堂 www.gkket.com

0

主题

202

回帖

444

积分

注册会员

积分
444
发表于 2021-5-20 19:38:12 | 显示全部楼层
激动人心,无法言表!
工控课堂 www.gkket.com

0

主题

118

回帖

276

积分

注册会员

积分
276
发表于 2021-5-21 11:14:05 | 显示全部楼层
太生气了,无法HOLD啦 >_<......
工控课堂 www.gkket.com

0

主题

60

回帖

84

积分

新手上路

积分
84
发表于 2025-11-30 23:40:00 | 显示全部楼层
赞同 + 10086,没毛病,完全没毛病
工控课堂 www.gkket.com

0

主题

120

回帖

205

积分

注册会员

积分
205
发表于 2025-11-30 23:57:11 | 显示全部楼层
原来还有这种操作,长见识了!
工控课堂 www.gkket.com

0

主题

102

回帖

169

积分

新手上路

积分
169
发表于 2025-12-1 00:21:24 | 显示全部楼层
占个楼慢慢看,先马克一下
楼主辛苦啦,期待下一篇分享
工控课堂 www.gkket.com

0

主题

69

回帖

105

积分

新手上路

积分
105
发表于 2025-12-1 00:32:56 | 显示全部楼层
蹲一波同款,有没有小伙伴推荐?
工控课堂 www.gkket.com

0

主题

178

回帖

383

积分

注册会员

积分
383
发表于 2025-12-1 12:34:38 | 显示全部楼层
浅评一下:内容优质,值得推荐~
工控课堂 www.gkket.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|手机版|免责声明|本站介绍|工控课堂 ( 沪ICP备20008691号-1 )

GMT+8, 2025-12-22 20:12 , Processed in 0.082210 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表