Skip to content

Commit 0d4c898

Browse files
committed
在不使用ExportServicesAttribute指定导出类型时,尝试自动获取导出类型
1 parent 64e7bcb commit 0d4c898

9 files changed

Lines changed: 138 additions & 28 deletions

File tree

samples/SampleModule5/SRRProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
namespace SampleModule5
66
{
77
//使用Scoped确保每个请求不一样
8-
[ExportScopedServices(typeof(IRequestRandomProvider))]
8+
[ExportScopedServices]
9+
//[ExportScopedServices(typeof(IRequestRandomProvider))]
910
public class SRRProvider : IRequestRandomProvider
1011
{
1112
public int Random()

samples/SampleModule5/TRProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
namespace SampleModule5
66
{
77
//使用Transient确保每次获取不一样
8-
[ExportTransientServices(typeof(IRandomProvider))]
8+
[ExportTransientServices]
9+
//[ExportTransientServices(typeof(IRandomProvider))]
910
public class TRProvider : IRandomProvider
1011
{
1112
public int Random()

src/Cuture.Extensions.Modularity/Attributes/ExportScopedServicesAttribute.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ public class ExportScopedServicesAttribute : ExportServicesAttribute
1212
{
1313
#region Public 构造函数
1414

15-
/// <summary>
16-
/// <inheritdoc cref="ExportScopedServicesAttribute"/>
17-
/// </summary>
18-
/// <param name="exportTypes"></param>
15+
/// <inheritdoc cref="ExportScopedServicesAttribute(AddDIMode, Type[])"/>
1916
public ExportScopedServicesAttribute(params Type[] exportTypes) : base(ServiceLifetime.Scoped, exportTypes)
2017
{
2118
}
@@ -24,7 +21,7 @@ public ExportScopedServicesAttribute(params Type[] exportTypes) : base(ServiceLi
2421
/// <inheritdoc cref="ExportScopedServicesAttribute"/>
2522
/// </summary>
2623
/// <param name="addMode">添加到DI容器的方式</param>
27-
/// <param name="exportTypes"></param>
24+
/// <param name="exportTypes"><inheritdoc cref="ExportServicesAttribute(byte)"/></param>
2825
public ExportScopedServicesAttribute(AddDIMode addMode, params Type[] exportTypes) : base(ServiceLifetime.Scoped, addMode, exportTypes)
2926
{
3027
}

src/Cuture.Extensions.Modularity/Attributes/ExportServicesAttribute.cs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,19 @@ public class ExportServicesAttribute : Attribute, IExportServicesProvider
5151

5252
#region Public 构造函数
5353

54-
/// <summary>
55-
/// <inheritdoc cref="ExportServicesAttribute"/>
56-
/// </summary>
57-
/// <param name="lifetime">导出服务的生命周期</param>
58-
/// <param name="exportTypes"></param>
54+
/// <inheritdoc cref="ExportServicesAttribute(ServiceLifetime, AddDIMode, Type[])"/>
5955
public ExportServicesAttribute(ServiceLifetime lifetime, params Type[] exportTypes)
6056
{
6157
Lifetime = lifetime;
62-
ExportTypes = exportTypes.IsNullOrEmpty()
63-
? throw new ArgumentOutOfRangeException(nameof(exportTypes), 0, "exportTypes cannot be less than 1 item.")
64-
: exportTypes;
58+
ExportTypes = exportTypes;
6559
}
6660

6761
/// <summary>
6862
/// <inheritdoc cref="ExportServicesAttribute"/>
6963
/// </summary>
7064
/// <param name="lifetime">导出服务的生命周期</param>
7165
/// <param name="addMode">添加到DI容器的方式</param>
72-
/// <param name="exportTypes"></param>
66+
/// <param name="exportTypes"><inheritdoc cref="ExportServicesAttribute(byte)"/></param>
7367
public ExportServicesAttribute(ServiceLifetime lifetime, AddDIMode addMode, params Type[] exportTypes) : this(lifetime, exportTypes)
7468
{
7569
AddDIMode = addMode;
@@ -97,6 +91,24 @@ public ExportServicesAttribute(ServiceLifetime lifetime, Type exportTypeDiscover
9791
AddDIMode = addMode;
9892
}
9993

94+
/// <summary>
95+
///
96+
/// </summary>
97+
/// <param name="exportTypes">
98+
/// 导出的服务类型<para/>
99+
/// 未明确指定时,将会尝试自动获取接口类型(排除IDisposable、IAsyncDisposable)<para/>
100+
/// 如果自动获取到的接口类型数量不等于 1 个,则会抛出异常<para/>
101+
/// 自动获取方法参见 <see cref="CutureExtensionsModularityTypeReflectionExtensions.GetMostLikelyDirectInterfaces"/><para/>
102+
/// ------------------<para/>
103+
/// Note!!! 使用自动导出时,务必测试是否符合预期。<para/>
104+
/// </param>
105+
/// <exception cref="NotImplementedException"></exception>
106+
protected ExportServicesAttribute(byte exportTypes)
107+
{
108+
//此构造函数仅用于引用文档
109+
throw new NotImplementedException();
110+
}
111+
100112
#endregion Public 构造函数
101113

102114
#region Public 方法
@@ -108,7 +120,21 @@ public virtual IEnumerable<Type> GetExportServiceTypes(Type targetType)
108120

109121
if (ExportTypeDiscovererType is null)
110122
{
111-
return ExportTypes;
123+
if (!ExportTypes.IsNullOrEmpty())
124+
{
125+
return ExportTypes;
126+
}
127+
var types = targetType.GetMostLikelyDirectInterfacesExcludeDefaults()?.ToArray();
128+
if (types is null
129+
|| !types.Any())
130+
{
131+
throw new ModularityException($"Can not get export service for type {targetType} automatically . Must use {nameof(ExportServicesAttribute)} define it clearly .");
132+
}
133+
else if (types.Length > 1)
134+
{
135+
throw new ModularityException($"More than one interface was got by automatically get the export service interface for type {targetType} . Must use {nameof(ExportServicesAttribute)} define it clearly .");
136+
}
137+
return types.Take(1);
112138
}
113139
else
114140
{

src/Cuture.Extensions.Modularity/Attributes/ExportSingletonServicesAttribute.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ public class ExportSingletonServicesAttribute : ExportServicesAttribute
1212
{
1313
#region Public 构造函数
1414

15-
/// <summary>
16-
/// <inheritdoc cref="ExportSingletonServicesAttribute"/>
17-
/// </summary>
18-
/// <param name="exportTypes"></param>
15+
/// <inheritdoc cref="ExportSingletonServicesAttribute(AddDIMode, Type[])"/>
1916
public ExportSingletonServicesAttribute(params Type[] exportTypes) : base(ServiceLifetime.Singleton, exportTypes)
2017
{
2118
}
@@ -24,7 +21,7 @@ public ExportSingletonServicesAttribute(params Type[] exportTypes) : base(Servic
2421
/// <inheritdoc cref="ExportSingletonServicesAttribute"/>
2522
/// </summary>
2623
/// <param name="addMode">添加到DI容器的方式</param>
27-
/// <param name="exportTypes"></param>
24+
/// <param name="exportTypes"><inheritdoc cref="ExportServicesAttribute(byte)"/></param>
2825
public ExportSingletonServicesAttribute(AddDIMode addMode, params Type[] exportTypes) : base(ServiceLifetime.Singleton, addMode, exportTypes)
2926
{
3027
}

src/Cuture.Extensions.Modularity/Attributes/ExportTransientServicesAttribute.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ public class ExportTransientServicesAttribute : ExportServicesAttribute
1212
{
1313
#region Public 构造函数
1414

15-
/// <summary>
16-
/// <inheritdoc cref="ExportTransientServicesAttribute"/>
17-
/// </summary>
18-
/// <param name="exportTypes"></param>
15+
/// <inheritdoc cref="ExportTransientServicesAttribute(AddDIMode, Type[])"/>
1916
public ExportTransientServicesAttribute(params Type[] exportTypes) : base(ServiceLifetime.Transient, exportTypes)
2017
{
2118
}
@@ -24,7 +21,7 @@ public ExportTransientServicesAttribute(params Type[] exportTypes) : base(Servic
2421
/// <inheritdoc cref="ExportTransientServicesAttribute"/>
2522
/// </summary>
2623
/// <param name="addMode">添加到DI容器的方式</param>
27-
/// <param name="exportTypes"></param>
24+
/// <param name="exportTypes"><inheritdoc cref="ExportServicesAttribute(byte)"/></param>
2825
public ExportTransientServicesAttribute(AddDIMode addMode, params Type[] exportTypes) : base(ServiceLifetime.Transient, addMode, exportTypes)
2926
{
3027
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
namespace System
5+
{
6+
/// <summary>
7+
///
8+
/// </summary>
9+
public static class CutureExtensionsModularityTypeReflectionExtensions
10+
{
11+
#region Public 方法
12+
13+
/// <summary>
14+
/// 获取类型最有可能的直接接口<para/>
15+
/// C#反射不能只获取代码中的直接继承接口,会获取间接继承的接口。通过一些简单的排除方法获取最有可能的接口,但不太能保证符合意图<para/>
16+
/// https://stackoverflow.com/questions/5318685/get-only-direct-interface-instead-of-all <para/>
17+
/// https://stackoverflow.com/questions/1613867/how-do-i-know-when-an-interface-is-directly-implemented-in-a-type-ignoring-inheri <para/>
18+
/// </summary>
19+
/// <param name="type"></param>
20+
/// <returns></returns>
21+
public static IEnumerable<Type> GetMostLikelyDirectInterfaces(this Type type)
22+
{
23+
var interfaces = type.BaseType is null
24+
? type.GetInterfaces()
25+
: type.GetInterfaces().Except(type.BaseType.GetInterfaces());
26+
return interfaces.Except(interfaces.SelectMany(t => t.GetInterfaces()));
27+
}
28+
29+
#endregion Public 方法
30+
}
31+
}

src/Cuture.Extensions.Modularity/Internal/Extensions/TypeExtensions.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,66 @@ public static void ThrowIfNotStandardAppModule(this Type type)
143143
}
144144
}
145145

146+
#region MostLikelyDirectInterfaces
147+
148+
private static WeakReference<Type[]?> s_defaultExcludeTypes = new(null);
149+
150+
/// <summary>
151+
/// <inheritdoc cref="CutureExtensionsModularityTypeReflectionExtensions.GetMostLikelyDirectInterfaces"/>
152+
/// </summary>
153+
/// <param name="type"></param>
154+
/// <param name="excludeTypes">要排除的类型</param>
155+
/// <returns></returns>
156+
public static IEnumerable<Type> GetMostLikelyDirectInterfaces(this Type? type, IEnumerable<Type> excludeTypes)
157+
{
158+
if (type is null)
159+
{
160+
return Array.Empty<Type>();
161+
}
162+
var types = type.GetMostLikelyDirectInterfaces().Except(excludeTypes).ToArray();
163+
return types.Length > 0 ? types : GetMostLikelyDirectInterfaces(type.BaseType, excludeTypes);
164+
}
165+
166+
/// <summary>
167+
/// <inheritdoc cref="CutureExtensionsModularityTypeReflectionExtensions.GetMostLikelyDirectInterfaces"/>
168+
/// 排除默认的类型 IDisposable IAsyncDisposable
169+
/// </summary>
170+
/// <param name="type"></param>
171+
/// <returns></returns>
172+
public static IEnumerable<Type> GetMostLikelyDirectInterfacesExcludeDefaults(this Type? type)
173+
{
174+
if (type is null)
175+
{
176+
return Array.Empty<Type>();
177+
}
178+
return type.GetMostLikelyDirectInterfaces(GetDefaultExcludeTypes());
179+
}
180+
181+
private static Type[] GetDefaultExcludeTypes()
182+
{
183+
if (s_defaultExcludeTypes.TryGetTarget(out var types))
184+
{
185+
return types ?? Array.Empty<Type>();
186+
}
187+
lock (s_defaultExcludeTypes)
188+
{
189+
if (s_defaultExcludeTypes.TryGetTarget(out types))
190+
{
191+
return types ?? Array.Empty<Type>();
192+
}
193+
types = new[] {
194+
typeof(IDisposable),
195+
#if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
196+
typeof(IAsyncDisposable)
197+
#endif
198+
};
199+
s_defaultExcludeTypes.SetTarget(types);
200+
return types;
201+
}
202+
}
203+
204+
#endregion MostLikelyDirectInterfaces
205+
146206
#endregion Public 方法
147207
}
148208
}

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
<!--Package Info-->
3131
<PropertyGroup>
32-
<VersionPrefix>1.1.4</VersionPrefix>
32+
<VersionPrefix>1.1.5</VersionPrefix>
3333

3434
<PackageIdPrefix>Cuture.Extensions</PackageIdPrefix>
3535
<Authors>Stratos</Authors>

0 commit comments

Comments
 (0)