mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
fixup dependency injection
This commit is contained in:
212
src/Snap.Hutao/Snap.Hutao/Core/TypeNameHelper.cs
Normal file
212
src/Snap.Hutao/Snap.Hutao/Core/TypeNameHelper.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 类型名称帮助类
|
||||
/// Directly copied from .NET Runtime library
|
||||
/// </summary>
|
||||
internal static class TypeNameHelper
|
||||
{
|
||||
private const char DefaultNestedTypeDelimiter = '+';
|
||||
|
||||
private static readonly Dictionary<Type, string> BuiltInTypeNames = new()
|
||||
{
|
||||
{ typeof(void), "void" },
|
||||
{ typeof(bool), "bool" },
|
||||
{ typeof(byte), "byte" },
|
||||
{ typeof(char), "char" },
|
||||
{ typeof(decimal), "decimal" },
|
||||
{ typeof(double), "double" },
|
||||
{ typeof(float), "float" },
|
||||
{ typeof(int), "int" },
|
||||
{ typeof(long), "long" },
|
||||
{ typeof(object), "object" },
|
||||
{ typeof(sbyte), "sbyte" },
|
||||
{ typeof(short), "short" },
|
||||
{ typeof(string), "string" },
|
||||
{ typeof(uint), "uint" },
|
||||
{ typeof(ulong), "ulong" },
|
||||
{ typeof(ushort), "ushort" },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象类型的显示名称
|
||||
/// </summary>
|
||||
/// <param name="item">物品</param>
|
||||
/// <param name="fullName">是否全名</param>
|
||||
/// <returns>对象类型的显示名称</returns>
|
||||
[return: NotNullIfNotNull(nameof(item))]
|
||||
public static string? GetTypeDisplayName(object? item, bool fullName = true)
|
||||
{
|
||||
return item == null ? null : GetTypeDisplayName(item.GetType(), fullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pretty print a type name.
|
||||
/// </summary>
|
||||
/// <param name="type">The <see cref="Type"/>.</param>
|
||||
/// <param name="fullName"><c>true</c> to print a fully qualified name.</param>
|
||||
/// <param name="includeGenericParameterNames"><c>true</c> to include generic parameter names.</param>
|
||||
/// <param name="includeGenericParameters"><c>true</c> to include generic parameters.</param>
|
||||
/// <param name="nestedTypeDelimiter">Character to use as a delimiter in nested type names</param>
|
||||
/// <returns>The pretty printed type name.</returns>
|
||||
public static string GetTypeDisplayName(Type type, bool fullName = true, bool includeGenericParameterNames = false, bool includeGenericParameters = true, char nestedTypeDelimiter = DefaultNestedTypeDelimiter)
|
||||
{
|
||||
StringBuilder? builder = null;
|
||||
string? name = ProcessType(ref builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames, includeGenericParameters, nestedTypeDelimiter));
|
||||
return name ?? builder?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
private static string? ProcessType(ref StringBuilder? builder, Type type, in DisplayNameOptions options)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
Type[] genericArguments = type.GetGenericArguments();
|
||||
builder ??= new StringBuilder();
|
||||
ProcessGenericType(builder, type, genericArguments, genericArguments.Length, options);
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
builder ??= new StringBuilder();
|
||||
ProcessArrayType(builder, type, options);
|
||||
}
|
||||
else if (BuiltInTypeNames.TryGetValue(type, out string? builtInName))
|
||||
{
|
||||
if (builder is null)
|
||||
{
|
||||
return builtInName;
|
||||
}
|
||||
|
||||
builder.Append(builtInName);
|
||||
}
|
||||
else if (type.IsGenericParameter)
|
||||
{
|
||||
if (options.IncludeGenericParameterNames)
|
||||
{
|
||||
if (builder is null)
|
||||
{
|
||||
return type.Name;
|
||||
}
|
||||
|
||||
builder.Append(type.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string name = options.FullName ? type.FullName! : type.Name;
|
||||
|
||||
if (builder is null)
|
||||
{
|
||||
if (options.NestedTypeDelimiter != DefaultNestedTypeDelimiter)
|
||||
{
|
||||
return name.Replace(DefaultNestedTypeDelimiter, options.NestedTypeDelimiter);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
builder.Append(name);
|
||||
if (options.NestedTypeDelimiter != DefaultNestedTypeDelimiter)
|
||||
{
|
||||
builder.Replace(DefaultNestedTypeDelimiter, options.NestedTypeDelimiter, builder.Length - name.Length, name.Length);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void ProcessArrayType(StringBuilder builder, Type type, in DisplayNameOptions options)
|
||||
{
|
||||
Type innerType = type;
|
||||
while (innerType.IsArray)
|
||||
{
|
||||
innerType = innerType.GetElementType()!;
|
||||
}
|
||||
|
||||
ProcessType(ref builder!, innerType, options);
|
||||
|
||||
while (type.IsArray)
|
||||
{
|
||||
builder.Append('[');
|
||||
builder.Append(',', type.GetArrayRank() - 1);
|
||||
builder.Append(']');
|
||||
type = type.GetElementType()!;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessGenericType(StringBuilder builder, Type type, Type[] genericArguments, int length, in DisplayNameOptions options)
|
||||
{
|
||||
int offset = 0;
|
||||
if (type.IsNested)
|
||||
{
|
||||
offset = type.DeclaringType!.GetGenericArguments().Length;
|
||||
}
|
||||
|
||||
if (options.FullName)
|
||||
{
|
||||
if (type.IsNested)
|
||||
{
|
||||
ProcessGenericType(builder, type.DeclaringType!, genericArguments, offset, options);
|
||||
builder.Append(options.NestedTypeDelimiter);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(type.Namespace))
|
||||
{
|
||||
builder.Append(type.Namespace);
|
||||
builder.Append('.');
|
||||
}
|
||||
}
|
||||
|
||||
int genericPartIndex = type.Name.IndexOf('`');
|
||||
if (genericPartIndex <= 0)
|
||||
{
|
||||
builder.Append(type.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
builder.Append(type.Name, 0, genericPartIndex);
|
||||
|
||||
if (options.IncludeGenericParameters)
|
||||
{
|
||||
builder.Append('<');
|
||||
for (int i = offset; i < length; i++)
|
||||
{
|
||||
ProcessType(ref builder!, genericArguments[i], options);
|
||||
if (i + 1 == length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.Append(',');
|
||||
if (options.IncludeGenericParameterNames || !genericArguments[i + 1].IsGenericParameter)
|
||||
{
|
||||
builder.Append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append('>');
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct DisplayNameOptions
|
||||
{
|
||||
public DisplayNameOptions(bool fullName, bool includeGenericParameterNames, bool includeGenericParameters, char nestedTypeDelimiter)
|
||||
{
|
||||
FullName = fullName;
|
||||
IncludeGenericParameters = includeGenericParameters;
|
||||
IncludeGenericParameterNames = includeGenericParameterNames;
|
||||
NestedTypeDelimiter = nestedTypeDelimiter;
|
||||
}
|
||||
|
||||
public bool FullName { get; }
|
||||
|
||||
public bool IncludeGenericParameters { get; }
|
||||
|
||||
public bool IncludeGenericParameterNames { get; }
|
||||
|
||||
public char NestedTypeDelimiter { get; }
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,8 @@ namespace Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[UseDynamicSecret]
|
||||
[HttpClient(HttpClientConfiguration.XRpc, typeof(IUserClient))]
|
||||
[HttpClient(HttpClientConfiguration.XRpc)]
|
||||
[Injection(InjectAs.Transient, typeof(IUserClient))]
|
||||
internal sealed class UserClient : IUserClient
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
@@ -24,12 +25,13 @@ internal sealed class UserClient : IUserClient
|
||||
/// <summary>
|
||||
/// 构造一个新的用户信息客户端
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="httpClientFactory">http客户端工厂</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public UserClient(HttpClient httpClient, JsonSerializerOptions options, ILogger<UserClient> logger)
|
||||
public UserClient(IHttpClientFactory httpClientFactory, JsonSerializerOptions options, ILogger<UserClient> logger)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
httpClient = httpClientFactory.CreateClient(nameof(UserClient));
|
||||
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ namespace Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||
/// 用户信息客户端 Hoyolab版
|
||||
/// </summary>
|
||||
[UseDynamicSecret]
|
||||
[HttpClient(HttpClientConfiguration.XRpc, typeof(IUserClient))]
|
||||
[HttpClient(HttpClientConfiguration.XRpc)]
|
||||
[Injection(InjectAs.Transient, typeof(IUserClient))]
|
||||
internal sealed class UserClientOversea : IUserClient
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
@@ -23,12 +24,13 @@ internal sealed class UserClientOversea : IUserClient
|
||||
/// <summary>
|
||||
/// 构造一个新的用户信息客户端
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="httpClientFactory">http客户端工厂</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public UserClientOversea(HttpClient httpClient, JsonSerializerOptions options, ILogger<UserClientOversea> logger)
|
||||
public UserClientOversea(IHttpClientFactory httpClientFactory, JsonSerializerOptions options, ILogger<UserClientOversea> logger)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
httpClient = httpClientFactory.CreateClient(nameof(UserClientOversea));
|
||||
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ namespace Snap.Hutao.Web.Hoyolab.Passport;
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[UseDynamicSecret]
|
||||
[HttpClient(HttpClientConfiguration.XRpc2, typeof(IPassportClient))]
|
||||
[HttpClient(HttpClientConfiguration.XRpc2)]
|
||||
[Injection(InjectAs.Transient, typeof(IPassportClient))]
|
||||
internal sealed class PassportClient2 : IPassportClient
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
@@ -26,12 +27,13 @@ internal sealed class PassportClient2 : IPassportClient
|
||||
/// <summary>
|
||||
/// 构造一个新的通行证客户端
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="httpClientFactory">http客户端工厂</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public PassportClient2(HttpClient httpClient, JsonSerializerOptions options, ILogger<PassportClient> logger)
|
||||
public PassportClient2(IHttpClientFactory httpClientFactory, JsonSerializerOptions options, ILogger<PassportClient> logger)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
httpClient = httpClientFactory.CreateClient(nameof(PassportClient2));
|
||||
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace Snap.Hutao.Web.Hoyolab.Passport;
|
||||
/// <summary>
|
||||
/// 通行证客户端 XRPC 版
|
||||
/// </summary>
|
||||
[HttpClient(HttpClientConfiguration.XRpc3, typeof(IPassportClient))]
|
||||
[HttpClient(HttpClientConfiguration.XRpc3)]
|
||||
[Injection(InjectAs.Transient, typeof(IPassportClient))]
|
||||
internal sealed class PassportClientOversea : IPassportClient
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
@@ -25,12 +26,13 @@ internal sealed class PassportClientOversea : IPassportClient
|
||||
/// <summary>
|
||||
/// 构造一个新的国际服通行证客户端
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="httpClientFactory">http客户端工厂</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public PassportClientOversea(HttpClient httpClient, JsonSerializerOptions options, ILogger<PassportClientOversea> logger)
|
||||
public PassportClientOversea(IHttpClientFactory httpClientFactory, JsonSerializerOptions options, ILogger<PassportClientOversea> logger)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
httpClient = httpClientFactory.CreateClient(nameof(PassportClientOversea));
|
||||
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[UseDynamicSecret]
|
||||
[HttpClient(HttpClientConfiguration.XRpc, typeof(IGameRecordClient))]
|
||||
[HttpClient(HttpClientConfiguration.XRpc)]
|
||||
[PrimaryHttpMessageHandler(UseCookies = false)]
|
||||
[Injection(InjectAs.Transient, typeof(IGameRecordClient))]
|
||||
internal sealed class GameRecordClient : IGameRecordClient
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
@@ -28,14 +29,14 @@ internal sealed class GameRecordClient : IGameRecordClient
|
||||
/// <summary>
|
||||
/// 构造一个新的游戏记录提供器
|
||||
/// </summary>
|
||||
/// <param name="httpClient">请求器</param>
|
||||
/// <param name="httpClientFactory">请求器工厂</param>
|
||||
/// <param name="serviceProvider">访问提供器</param>
|
||||
public GameRecordClient(HttpClient httpClient, IServiceProvider serviceProvider)
|
||||
public GameRecordClient(IHttpClientFactory httpClientFactory, IServiceProvider serviceProvider)
|
||||
{
|
||||
options = serviceProvider.GetRequiredService<JsonSerializerOptions>();
|
||||
logger = serviceProvider.GetRequiredService<ILogger<GameRecordClient>>();
|
||||
httpClient = httpClientFactory.CreateClient(nameof(GameRecordClient));
|
||||
|
||||
this.httpClient = httpClient;
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||
/// Hoyoverse game record provider
|
||||
/// </summary>
|
||||
[UseDynamicSecret]
|
||||
[HttpClient(HttpClientConfiguration.XRpc3, typeof(IGameRecordClient))]
|
||||
[HttpClient(HttpClientConfiguration.XRpc3)]
|
||||
[PrimaryHttpMessageHandler(UseCookies = false)]
|
||||
[Injection(InjectAs.Transient, typeof(IGameRecordClient))]
|
||||
internal sealed class GameRecordClientOversea : IGameRecordClient
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
@@ -26,12 +27,13 @@ internal sealed class GameRecordClientOversea : IGameRecordClient
|
||||
/// <summary>
|
||||
/// 构造一个新的游戏记录提供器
|
||||
/// </summary>
|
||||
/// <param name="httpClient">请求器</param>
|
||||
/// <param name="httpClientFactory">请求器工厂</param>
|
||||
/// <param name="options">json序列化选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public GameRecordClientOversea(HttpClient httpClient, JsonSerializerOptions options, ILogger<GameRecordClient> logger)
|
||||
public GameRecordClientOversea(IHttpClientFactory httpClientFactory, JsonSerializerOptions options, ILogger<GameRecordClient> logger)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
httpClient = httpClientFactory.CreateClient(nameof(GameRecordClientOversea));
|
||||
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user