Novidades do C# 8.0: Default interface methods

Olá, neste artigo eu vou escrever sobre a novidade do C# 8 default interface methods.
Neste artigo você poderá ver um resumo das novidades que eu acho mais relevantes que vieram no C# 8.

Index:
Antes do C# 8
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public interface ILimit
{
IFilterBuilder Limit(in uint limit);
}

public interface ISkip
{
IFilterBuilder Skip(in uint skip);
}

public interface ISelect
{
IFilterBuilder Select(params string[] fields);
}

public interface IFilterBuilder : ILimit, ISkip, ISelect
{
string Build();
}

public sealed class FilterBuilder : IFilterBuilder
{
private readonly ICollection<string> filters;

private FilterBuilder() => this.filters = new List<string>();

public IFilterBuilder Skip(in uint skip)
{
var newSkip = skip < 1
? 1
: skip;

this.filters.Add($"filter[skip]={newSkip}");
return this;
}

public IFilterBuilder Limit(in uint limit)
{
var newLimit = limit < 1
? 1
: limit;

this.filters.Add($"filter[limit]={newLimit}");
return this;
}

public IFilterBuilder Select(params string[] fields)
{
foreach (var field in fields)
{
this.filters.Add($"filter[fields][{field}]=true");
}

return this;
}

public string Build() => string.Join("&", this.filters);

public static IFilterBuilder NewFilterBuilder() => new FilterBuilder();
}
Antes do C# 8 (uma opção com interface extensions)

Este exemplo foi inspirado no artigo Pseudo Traits in C#, que traz uma abordagem de como podemos fazer praticamente a mesma coisa sem precisar desta nova funcionalidade.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public interface IFilterBase
{
IFilterBuilder AddFilters(params string[] values);
}

public interface ILimit : IFilterBase
{
}

public static partial class FilterExtension
{
public static IFilterBuilder Limit(this ILimit @this, uint limit)
{
var newLimit = limit < 1
? 1
: limit;

return @this
.AddFilters($"filter[limit]={newLimit}");
}
}

public interface ISkip : IFilterBase
{
}

public static partial class FilterExtension
{
public static IFilterBuilder Skip(this ISkip @this, uint skip)
{
var newSkip = skip < 1
? 1
: skip;

return @this
.AddFilters($"filter[skip]={newSkip}");
}
}

public interface ISelect : IFilterBase
{
}

public static partial class FilterExtension
{
public static IFilterBuilder Select(this ISelect @this, params string[] fields) => @this
.AddFilters(fields
.Select(field => $"filter[fields][{field}]=true")
.ToArray());
}

public interface IFilterBuilder : ILimit, ISkip, ISelect
{
string Build();
}

public sealed class FilterBuilder : IFilterBuilder
{
private readonly ICollection<string> filters;

private FilterBuilder() => this.filters = new List<string>();

public string Build() => string.Join("&", this.filters);

public IFilterBuilder AddFilters(params string[] values)
{
foreach (var value in values)
{
this.filters.Add(value);
}

return this;
}

public static IFilterBuilder NewFilterBuilder() => new FilterBuilder();
}
Depois do C# 8
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public interface IFilterBase
{
IFilterBuilder AddFilters(params string[] values);
}

public interface ISkip : IFilterBase
{
IFilterBuilder Skip(in uint skip)
{
var newSkip = skip < 1
? 1
: skip;

return this
.AddFilters($"filter[skip]={newSkip}");
}
}

public interface ILimit : IFilterBase
{
IFilterBuilder Limit(in uint limit)
{
var newLimit = limit < 1
? 1
: limit;

return this
.AddFilters($"filter[limit]={newLimit}");
}
}

public interface ISelect : IFilterBase
{
public IFilterBuilder Select(params string[] fields) => this
.AddFilters(fields
.Select(field => $"filter[fields][{field}]=true")
.ToArray());
}

public interface IFilterBuilder : ILimit, ISkip, ISelect
{
string Build();
}

public sealed class FilterBuilder : IFilterBuilder
{
private readonly ICollection<string> filters;

private FilterBuilder() => this.filters = new List<string>();

public string Build() => string.Join("&", this.filters);

public IFilterBuilder AddFilters(params string[] values)
{
foreach (var value in values)
{
this.filters.Add(value);
}

return this;
}

public static IFilterBuilder NewFilterBuilder() => new FilterBuilder();
}
Considerações finais

Esta nova funcionalidade dividiu um pouco a opinião da comunidade, alguns gostaram e outros nem tanto, abaixo dois artigos que ilustram bem essas opiniões:

O último exemplo com a implementação desta nova funcionalidade foi retirado do projeto Http.Query.Filter.

Obrigado pela visita 🙂!