mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-18 01:16:44 +08:00
发布:3.1.3
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<BaseVersion>3.1.2</BaseVersion>
|
||||
<BaseVersion>3.1.3</BaseVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<TouchSocketVersion>$(BaseVersion)</TouchSocketVersion>
|
||||
|
||||
@@ -217,7 +217,7 @@ public class WebSocketDmtpService : ConnectableService<WebSocketDmtpSessionClien
|
||||
/// 尝试添加客户端到集合中。
|
||||
/// </summary>
|
||||
/// <param name="sessionClient">WebSocketDmtpSessionClient对象。</param>
|
||||
/// <returns>如果添加成功返回true,否则返回false。</returns>
|
||||
/// <returns>如果添加成功返回<see langword="true"/>,否则返回<see langword="false"/>。</returns>
|
||||
internal bool TryAdd(WebSocketDmtpSessionClient sessionClient)
|
||||
{
|
||||
return this.m_clients.TryAdd(sessionClient);
|
||||
@@ -228,7 +228,7 @@ public class WebSocketDmtpService : ConnectableService<WebSocketDmtpSessionClien
|
||||
/// </summary>
|
||||
/// <param name="id">客户端标识符。</param>
|
||||
/// <param name="sessionClient">移除的WebSocketDmtpSessionClient对象。</param>
|
||||
/// <returns>如果移除成功返回true,否则返回false。</returns>
|
||||
/// <returns>如果移除成功返回<see langword="true"/>,否则返回<see langword="false"/>。</returns>
|
||||
internal bool TryRemove(string id, out WebSocketDmtpSessionClient sessionClient)
|
||||
{
|
||||
return this.m_clients.TryRemoveClient(id, out sessionClient);
|
||||
|
||||
@@ -131,7 +131,7 @@ public sealed partial class TouchSocketBitConverter
|
||||
/// <summary>
|
||||
/// 判断当前字节序是否与系统字节序相同
|
||||
/// </summary>
|
||||
/// <returns>如果字节序相同返回true,否则返回false</returns>
|
||||
/// <returns>如果字节序相同返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsSameOfSet()
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ public static class CacheManagementExtensions
|
||||
/// <param name="key">要获取的缓存键。</param>
|
||||
/// <param name="value">输出参数,包含获取的缓存值。</param>
|
||||
/// <param name="update">是否更新缓存项的时间戳。</param>
|
||||
/// <returns>如果成功获取值则返回true,否则返回false。</returns>
|
||||
/// <returns>如果成功获取值则返回<see langword="true"/>,否则返回<see langword="false"/>。</returns>
|
||||
public static bool TryGetValue<TKey, TValue>(this ICache<TKey, TValue> cacheClient, TKey key, out TValue value, bool update = false)
|
||||
{
|
||||
// 从缓存中获取缓存项。
|
||||
|
||||
@@ -10,14 +10,16 @@
|
||||
// 感谢您的下载和使用
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: UnconditionalSuppressMessage("ReflectionAnalysis", "IL2104",
|
||||
Justification = "The list only contains types stored through the annotated setter111.")]
|
||||
|
||||
[assembly: UnconditionalSuppressMessage("ReflectionAnalysis", "IL3153",
|
||||
Justification = "The list only contains types stored through the annotated setter222.")]
|
||||
#endif
|
||||
//[PluginRaise(typeof(ILoadingConfigPlugin))]
|
||||
//[PluginRaise(typeof(ILoadedConfigPlugin))]
|
||||
//internal static partial class PluginRaiseExtension
|
||||
//{
|
||||
//}
|
||||
@@ -10,6 +10,8 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
/// <summary>
|
||||
@@ -21,4 +23,18 @@ public static class GlobalEnvironment
|
||||
/// 动态构建类型,默认使用IL
|
||||
/// </summary>
|
||||
public static DynamicBuilderType DynamicBuilderType { get; set; } = DynamicBuilderType.IL;
|
||||
|
||||
#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持动态代码
|
||||
/// </summary>
|
||||
public static bool IsDynamicCodeSupported => RuntimeFeature.IsDynamicCodeSupported;
|
||||
#else
|
||||
/// <summary>
|
||||
/// 是否支持动态代码
|
||||
/// </summary>
|
||||
public static bool IsDynamicCodeSupported => true;
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -20,7 +20,6 @@ namespace TouchSocket.Core;
|
||||
[FastConverter(typeof(MetadataFastBinaryConverter))]
|
||||
public sealed class Metadata : Dictionary<string, string>, IPackage
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置指定键的值。
|
||||
/// </summary>
|
||||
@@ -28,8 +27,16 @@ public sealed class Metadata : Dictionary<string, string>, IPackage
|
||||
/// <returns></returns>
|
||||
public new string this[string key]
|
||||
{
|
||||
get => this.TryGetValue(key, out var value) ? value : null;
|
||||
set => this.Add(key, value);
|
||||
get
|
||||
{
|
||||
ThrowHelper.ThrowArgumentNullExceptionIf(key, nameof(key));
|
||||
return this.TryGetValue(key, out var value) ? value : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
ThrowHelper.ThrowArgumentNullExceptionIf(key, nameof(key));
|
||||
base[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -40,15 +47,7 @@ public sealed class Metadata : Dictionary<string, string>, IPackage
|
||||
/// <returns>返回当前元数据对象,以支持链式调用。</returns>
|
||||
public new Metadata Add(string name, string value)
|
||||
{
|
||||
if (this.ContainsKey(name))
|
||||
{
|
||||
base[name] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Add(name, value);
|
||||
}
|
||||
|
||||
base[name] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public abstract class CacheDataHandlingAdapter : SingleStreamDataHandlingAdapter
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前缓存,
|
||||
/// 如果缓存超时,或者不存在,均会返回false。
|
||||
/// 如果缓存超时,或者不存在,均会返回<see langword="false"/>。
|
||||
/// 如果获取成功,则会清空内部缓存。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
@@ -132,7 +132,7 @@ public interface IBigFixedHeaderRequestInfo : IRequestInfo
|
||||
/// <summary>
|
||||
/// 当收到数据,由框架封送固定协议头。
|
||||
/// <para>您需要在此函数中,解析自己的固定包头,并且对<see cref="BodyLength"/>赋值后续数据的长度,然后返回True。</para>
|
||||
/// <para>如果返回false,则意味着放弃本次解析</para>
|
||||
/// <para>如果返回<see langword="false"/>,则意味着放弃本次解析</para>
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
@@ -125,7 +125,7 @@ public interface IBigUnfixedHeaderRequestInfo : IRequestInfo
|
||||
/// <summary>
|
||||
/// 当收到数据,由框架封送数据,您需要在此函数中,解析自己的数据包头。
|
||||
/// <para>如果满足包头的解析,请返回True,并且递增整个包头的长度到<see cref="ByteBlock.Position"/>,然后赋值<see cref="BodyLength"/></para>
|
||||
/// <para>如果返回false,意味着缓存剩余数据,此时如果仅仅是因为长度不足,则不必修改其他。</para>
|
||||
/// <para>如果返回<see langword="false"/>,意味着缓存剩余数据,此时如果仅仅是因为长度不足,则不必修改其他。</para>
|
||||
/// <para>但是如果是因为数据错误,则需要修改<see cref="ByteBlock.Position"/>到正确位置,如果都不正确,则设置<see cref="ByteBlock.Position"/>等于<see cref="ByteBlock.Length"/></para>
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
|
||||
@@ -133,7 +133,7 @@ public interface IFixedHeaderByteBlockRequestInfo : IRequestInfo
|
||||
/// <summary>
|
||||
/// 当收到数据,由框架封送固定协议头。
|
||||
/// <para>您需要在此函数中,解析自己的固定包头,并且对<see cref="BodyLength"/>赋值后续数据的长度,然后返回True。</para>
|
||||
/// <para>如果返回false,则意味着放弃本次解析</para>
|
||||
/// <para>如果返回<see langword="false"/>,则意味着放弃本次解析</para>
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
@@ -141,7 +141,7 @@ public interface IFixedHeaderByteBlockRequestInfo : IRequestInfo
|
||||
|
||||
/// <summary>
|
||||
/// 当收到数据,由框架封送有效载荷数据。
|
||||
/// <para>如果返回false,意味着放弃本次解析的所有数据,包括已经解析完成的Header</para>
|
||||
/// <para>如果返回<see langword="false"/>,意味着放弃本次解析的所有数据,包括已经解析完成的Header</para>
|
||||
/// </summary>
|
||||
/// <param name="byteBlock">载荷数据,注意:该字节块生命周期不受框架控制,请一定自行调用Dispose</param>
|
||||
/// <returns>是否成功有效</returns>
|
||||
|
||||
@@ -119,7 +119,7 @@ public interface IFixedHeaderRequestInfo : IRequestInfo
|
||||
/// <summary>
|
||||
/// 当收到数据,由框架封送固定协议头。
|
||||
/// <para>您需要在此函数中,解析自己的固定包头,并且对<see cref="BodyLength"/>赋值后续数据的长度,然后返回True。</para>
|
||||
/// <para>如果返回false,则意味着放弃本次解析</para>
|
||||
/// <para>如果返回<see langword="false"/>,则意味着放弃本次解析</para>
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
@@ -127,7 +127,7 @@ public interface IFixedHeaderRequestInfo : IRequestInfo
|
||||
|
||||
/// <summary>
|
||||
/// 当收到数据,由框架封送有效载荷数据。
|
||||
/// <para>如果返回false,意味着放弃本次解析的所有数据,包括已经解析完成的Header</para>
|
||||
/// <para>如果返回<see langword="false"/>,意味着放弃本次解析的所有数据,包括已经解析完成的Header</para>
|
||||
/// </summary>
|
||||
/// <param name="body">载荷数据</param>
|
||||
/// <returns>是否成功有效</returns>
|
||||
|
||||
@@ -31,7 +31,7 @@ public interface IUnfixedHeaderRequestInfo : IRequestInfo
|
||||
|
||||
/// <summary>
|
||||
/// 当收到数据,由框架封送有效载荷数据。
|
||||
/// <para>如果返回false,意味着放弃本次解析的所有数据,包括已经解析完成的Header</para>
|
||||
/// <para>如果返回<see langword="false"/>,意味着放弃本次解析的所有数据,包括已经解析完成的Header</para>
|
||||
/// </summary>
|
||||
/// <param name="body">载荷数据</param>
|
||||
/// <returns>是否成功有效</returns>
|
||||
@@ -40,7 +40,7 @@ public interface IUnfixedHeaderRequestInfo : IRequestInfo
|
||||
/// <summary>
|
||||
/// 当收到数据,由框架封送数据,您需要在此函数中,解析自己的数据包头。
|
||||
/// <para>如果满足包头的解析,请返回True,并且递增整个包头的长度到<see cref="ByteBlock.Position"/>,然后赋值<see cref="BodyLength"/></para>
|
||||
/// <para>如果返回false,意味着缓存剩余数据,此时如果仅仅是因为长度不足,则不必修改其他。</para>
|
||||
/// <para>如果返回<see langword="false"/>,意味着缓存剩余数据,此时如果仅仅是因为长度不足,则不必修改其他。</para>
|
||||
/// <para>但是如果是因为数据错误,则需要修改<see cref="ByteBlock.Position"/>到正确位置,如果都不正确,则设置<see cref="ByteBlock.Position"/>等于<see cref="ByteBlock.Length"/></para>
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
|
||||
@@ -69,10 +69,10 @@ public static class CollectionsExtension
|
||||
/// <param name="dictionary">要添加键值对的字典。</param>
|
||||
/// <param name="key">要添加的键。</param>
|
||||
/// <param name="value">要添加的值。</param>
|
||||
/// <returns>如果添加成功则返回true,否则返回false。</returns>
|
||||
/// <returns>如果添加成功则返回<see langword="true"/>,否则返回<see langword="false"/>。</returns>
|
||||
public static bool TryAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value)
|
||||
{
|
||||
// 如果字典中已经包含此键,则不添加,并返回false
|
||||
// 如果字典中已经包含此键,则不添加,并返回<see langword="false"/>
|
||||
if (dictionary.ContainsKey(key))
|
||||
{
|
||||
return false;
|
||||
@@ -97,11 +97,11 @@ public static class CollectionsExtension
|
||||
{
|
||||
if (dictionary.TryGetValue(key,out value))
|
||||
{
|
||||
// 如果字典中包含此键,则移除并返回true
|
||||
// 如果字典中包含此键,则移除并返回<see langword="true"/>
|
||||
dictionary.Remove(key);
|
||||
return true;
|
||||
}
|
||||
// 如果字典中不包含此键,则返回false
|
||||
// 如果字典中不包含此键,则返回<see langword="false"/>
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -39,11 +39,11 @@ public static class ReflectionExtension
|
||||
|
||||
private static string GenerateKey(MethodInfo method)
|
||||
{
|
||||
var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); // 使用类型名称
|
||||
var parameterTypes = method.GetParameters().Select(p => p.ParameterType); // 使用类型名称
|
||||
return GenerateKey(method.Name, parameterTypes);
|
||||
}
|
||||
|
||||
private static string GenerateKey(string methodName, Type[] parameterTypes)
|
||||
private static string GenerateKey(string methodName, IEnumerable<Type> parameterTypes)
|
||||
{
|
||||
// 将参数类型名称转换为合法的标识符
|
||||
var parameterTypeNames = string.Join("_", parameterTypes.Select(t => StringExtension.MakeIdentifier(t.GetRefOutType().Name)));
|
||||
@@ -145,28 +145,28 @@ public static class ReflectionExtension
|
||||
/// 检查属性是否可以公开写入
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">要检查的属性信息</param>
|
||||
/// <returns>如果属性可以公开写入则返回true,否则返回false</returns>
|
||||
/// <returns>如果属性可以公开写入则返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
public static bool CanPublicWrite(this PropertyInfo propertyInfo)
|
||||
{
|
||||
// 如果属性不支持写操作,则直接返回false
|
||||
// 如果属性不支持写操作,则直接返回<see langword="false"/>
|
||||
if (!propertyInfo.CanWrite)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果属性的设置方法为null,则表示不能写入,返回false
|
||||
// 如果属性的设置方法为null,则表示不能写入,返回<see langword="false"/>
|
||||
if (propertyInfo.SetMethod == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果属性的设置方法是公共的,并且接受一个参数,则认为该属性可以公开写入,返回true
|
||||
// 如果属性的设置方法是公共的,并且接受一个参数,则认为该属性可以公开写入,返回<see langword="true"/>
|
||||
if (propertyInfo.SetMethod.IsPublic && propertyInfo.SetMethod.GetParameters().Length == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果上述条件都不满足,则返回false
|
||||
// 如果上述条件都不满足,则返回<see langword="false"/>
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ public static class StringExtension
|
||||
/// 检查字符串是否具有有效值。
|
||||
/// </summary>
|
||||
/// <param name="str">要检查的字符串。</param>
|
||||
/// <returns>如果字符串不是null且非空格或制表符等,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果字符串不是null且非空格或制表符等,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public static bool HasValue([NotNullWhen(true)] this string str)
|
||||
{
|
||||
// 使用string.IsNullOrWhiteSpace方法检查字符串是否为null或包含仅空格或制表符等
|
||||
@@ -311,10 +311,10 @@ public static class StringExtension
|
||||
///<param name="value">待解析的字符串</param>
|
||||
///<param name="destinationType">目标数据类型</param>
|
||||
/// <param name="returnValue">解析后的值,输出参数</param>
|
||||
/// <returns>如果解析成功返回true,否则返回false</returns>
|
||||
/// <returns>如果解析成功返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
public static bool TryParseToType(string value, Type destinationType, out object returnValue)
|
||||
{
|
||||
// 如果字符串为空或只含空格,将returnValue设为默认值并返回true
|
||||
// 如果字符串为空或只含空格,将returnValue设为默认值并返回<see langword="true"/>
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
returnValue = default;
|
||||
@@ -421,7 +421,7 @@ public static class StringExtension
|
||||
returnValue = value;
|
||||
return true;
|
||||
}
|
||||
// 对空类型、对象类型或数据库空值类型,将returnValue设为默认值并返回false
|
||||
// 对空类型、对象类型或数据库空值类型,将returnValue设为默认值并返回<see langword="false"/>
|
||||
case TypeCode.Empty:
|
||||
case TypeCode.Object:
|
||||
case TypeCode.DBNull:
|
||||
|
||||
@@ -23,6 +23,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Buffers;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
@@ -206,7 +207,7 @@ public static class SystemExtension
|
||||
/// </summary>
|
||||
/// <param name="b">要检查的无符号长整型数值。</param>
|
||||
/// <param name="index">要检查的位的位置,从0到63。</param>
|
||||
/// <returns>如果指定位置的位为1,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果指定位置的位为1,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">当索引值不在0到63之间时,抛出此异常。</exception>
|
||||
public static bool GetBit(this ulong b, int index)
|
||||
{
|
||||
@@ -222,7 +223,7 @@ public static class SystemExtension
|
||||
/// </summary>
|
||||
/// <param name="b">要检查的无符号整型数值。</param>
|
||||
/// <param name="index">要检查的位的位置,从0到31。</param>
|
||||
/// <returns>如果指定位置的位为1,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果指定位置的位为1,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">当索引值不在0到31之间时,抛出此异常。</exception>
|
||||
public static bool GetBit(this uint b, int index)
|
||||
{
|
||||
@@ -238,7 +239,7 @@ public static class SystemExtension
|
||||
/// </summary>
|
||||
/// <param name="b">要检查的无符号短整型数值。</param>
|
||||
/// <param name="index">要检查的位的位置,从0到15。</param>
|
||||
/// <returns>如果指定位置的位为1,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果指定位置的位为1,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">当索引值不在0到15之间时,抛出此异常。</exception>
|
||||
public static bool GetBit(this ushort b, int index)
|
||||
{
|
||||
@@ -254,7 +255,7 @@ public static class SystemExtension
|
||||
/// </summary>
|
||||
/// <param name="b">要检查的字节型数值。</param>
|
||||
/// <param name="index">要检查的位的位置,从0到7。</param>
|
||||
/// <returns>如果指定位置的位为1,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果指定位置的位为1,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">当索引值不在0到7之间时,抛出此异常。</exception>
|
||||
public static bool GetBit(this byte b, int index)
|
||||
{
|
||||
@@ -632,6 +633,39 @@ public static class SystemExtension
|
||||
return type.IsPrimitive || type == typeof(string);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型的短确定性名称,支持泛型。
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDeterminantName(this Type type)
|
||||
{
|
||||
IEnumerable<Type> types;
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
types = type.GetGenericArguments();
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
types = new Type[] { type.GetElementType() };
|
||||
}
|
||||
else
|
||||
{
|
||||
types = [];
|
||||
}
|
||||
|
||||
var stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append(type.Namespace);
|
||||
stringBuilder.Append(type.Name);
|
||||
foreach (var item in types)
|
||||
{
|
||||
stringBuilder.Append(item.Namespace);
|
||||
stringBuilder.Append(item.Name);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
#endregion Type
|
||||
|
||||
#region Memory
|
||||
|
||||
@@ -60,7 +60,7 @@ public class FlowGate : Counter
|
||||
/// </remarks>
|
||||
public async Task AddCheckWaitAsync(long increment)
|
||||
{
|
||||
// 尝试增加计数器,如果返回true,则表示增加成功,需要进一步处理
|
||||
// 尝试增加计数器,如果返回<see langword="true"/>,则表示增加成功,需要进一步处理
|
||||
if (this.Increment(increment))
|
||||
{
|
||||
// 如果当前计数超过设定的最大值
|
||||
|
||||
@@ -377,7 +377,7 @@ public interface IByteBlock : IDisposable, IBufferWriter<byte>
|
||||
/// <summary>
|
||||
/// 读取是否为null。
|
||||
/// </summary>
|
||||
/// <returns>如果读取内容为null,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果读取内容为null,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
bool ReadIsNull();
|
||||
|
||||
/// <summary>
|
||||
|
||||
130
src/TouchSocket.Core/Reflection/DynamicMethodInfoBase.cs
Normal file
130
src/TouchSocket.Core/Reflection/DynamicMethodInfoBase.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
abstract class DynamicMethodInfoBase : IDynamicMethodInfo
|
||||
{
|
||||
public DynamicMethodInfoBase(MethodInfo method)
|
||||
{
|
||||
if (method.ReturnType == typeof(void))
|
||||
{
|
||||
this.ReturnKind = MethodReturnKind.Void;
|
||||
}
|
||||
else if (IsTypeAwaitable(method.ReturnType, out var returnType))
|
||||
{
|
||||
if (returnType is null)
|
||||
{
|
||||
this.ReturnKind = MethodReturnKind.Awaitable;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RealReturnType = returnType;
|
||||
this.ReturnKind = MethodReturnKind.AwaitableObject;
|
||||
}
|
||||
}
|
||||
else if (method.ReturnType == typeof(Task)|| method.ReturnType == typeof(ValueTask))
|
||||
{
|
||||
this.ReturnKind = MethodReturnKind.Awaitable;
|
||||
}
|
||||
else if (method.ReturnType.IsGenericType && (method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)|| method.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)))
|
||||
{
|
||||
this.RealReturnType = method.ReturnType.GetGenericArguments().First();
|
||||
this.ReturnKind = MethodReturnKind.AwaitableObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RealReturnType = method.ReturnType;
|
||||
this.ReturnKind = MethodReturnKind.Object;
|
||||
}
|
||||
}
|
||||
public Type RealReturnType { get; set; }
|
||||
|
||||
public MethodReturnKind ReturnKind { get; set; }
|
||||
|
||||
public async Task<object> GetResultAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] object result)
|
||||
{
|
||||
if (result is Task task)
|
||||
{
|
||||
await task.ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
if (this.ReturnKind== MethodReturnKind.AwaitableObject)
|
||||
{
|
||||
return DynamicMethodMemberAccessor.Default.GetValue(task, nameof(Task<object>.Result));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ThrowHelper.ThrowException("当源生成无法使用时,无法处理非Task的Awaitable对象。");
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract object Invoke(object instance, object[] parameters);
|
||||
|
||||
private static bool IsTypeAwaitable([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, out Type returnType)
|
||||
{
|
||||
returnType = null;
|
||||
// 1. 查找GetAwaiter实例方法(无参数)
|
||||
MethodInfo getAwaiterMethod = type.GetMethod("GetAwaiter", BindingFlags.Public | BindingFlags.Instance);
|
||||
if (getAwaiterMethod == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 获取Awaiter类型
|
||||
Type awaiterType = getAwaiterMethod.ReturnType;
|
||||
|
||||
// 3. 验证Awaiter是否实现必要的接口
|
||||
Type inotifyCompletion = typeof(System.Runtime.CompilerServices.INotifyCompletion);
|
||||
Type icriticalNotifyCompletion = typeof(System.Runtime.CompilerServices.ICriticalNotifyCompletion);
|
||||
|
||||
var implementsInterface = awaiterType.GetInterfaces().Any(i =>
|
||||
i == inotifyCompletion || i == icriticalNotifyCompletion);
|
||||
if (!implementsInterface)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 检查IsCompleted属性
|
||||
var isCompletedProp = awaiterType.GetProperty("IsCompleted", BindingFlags.Public | BindingFlags.Instance);
|
||||
if (isCompletedProp == null ||
|
||||
isCompletedProp.PropertyType != typeof(bool) ||
|
||||
!isCompletedProp.CanRead)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. 检查GetResult方法
|
||||
var getResultMethod = awaiterType.GetMethod("GetResult", BindingFlags.Public | BindingFlags.Instance);
|
||||
if (getResultMethod == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 6. 检查GetResult方法的返回类型
|
||||
if (getResultMethod.ReturnType == typeof(void))
|
||||
{
|
||||
returnType = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnType = getResultMethod.ReturnType;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
@@ -44,23 +45,23 @@ public class DynamicMethodMemberAccessor : IMemberAccessor
|
||||
public Func<Type, PropertyInfo[]> OnGetProperties { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object GetValue(object instance, string memberName)
|
||||
public object GetValue([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] object instance, string memberName)
|
||||
{
|
||||
return this.FindClassAccessor(instance).GetValue(instance, memberName);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetValue(object instance, string memberName, object newValue)
|
||||
public void SetValue([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] object instance, string memberName, object newValue)
|
||||
{
|
||||
this.FindClassAccessor(instance).SetValue(instance, memberName, newValue);
|
||||
}
|
||||
|
||||
private IMemberAccessor FindClassAccessor(object instance)
|
||||
private IMemberAccessor FindClassAccessor([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] object instance)
|
||||
{
|
||||
var typekey = instance.GetType();
|
||||
if (!this.m_classAccessors.TryGetValue(typekey, out var classAccessor))
|
||||
var typeKey = instance.GetType();
|
||||
if (!this.m_classAccessors.TryGetValue(typeKey, out var classAccessor))
|
||||
{
|
||||
var memberAccessor = new MemberAccessor(instance.GetType());
|
||||
var memberAccessor = new MemberAccessor(typeKey);
|
||||
if (this.OnGetFieldInfes != null)
|
||||
{
|
||||
memberAccessor.OnGetFieldInfos = this.OnGetFieldInfes;
|
||||
@@ -72,7 +73,7 @@ public class DynamicMethodMemberAccessor : IMemberAccessor
|
||||
}
|
||||
memberAccessor.Build();
|
||||
classAccessor = memberAccessor;
|
||||
this.m_classAccessors.TryAdd(typekey, classAccessor);
|
||||
this.m_classAccessors.TryAdd(typeKey, classAccessor);
|
||||
}
|
||||
return classAccessor;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
internal class ExpressionDynamicMethodInfo : DynamicMethodInfoBase
|
||||
{
|
||||
private Func<object, object[], object> m_func;
|
||||
public ExpressionDynamicMethodInfo(MethodInfo method) : base(method)
|
||||
{
|
||||
m_func = CreateExpressionInvoker(method);
|
||||
}
|
||||
|
||||
public override object Invoke(object instance, object[] parameters)
|
||||
{
|
||||
return m_func.Invoke(instance, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建表达式树调用
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <returns></returns>
|
||||
protected Func<object, object[], object> CreateExpressionInvoker(MethodInfo method)
|
||||
{
|
||||
var instance = Expression.Parameter(typeof(object), "instance");
|
||||
var parameters = Expression.Parameter(typeof(object[]), "parameters");
|
||||
|
||||
var instanceCast = method.IsStatic ? null : Expression.Convert(instance, method.DeclaringType);
|
||||
var parametersCast = method.GetParameters().Select((p, i) =>
|
||||
{
|
||||
var parameter = Expression.ArrayIndex(parameters, Expression.Constant(i));
|
||||
return Expression.Convert(parameter, p.ParameterType);
|
||||
});
|
||||
|
||||
var body = Expression.Call(instanceCast, method, parametersCast);
|
||||
|
||||
switch (this.ReturnKind)
|
||||
{
|
||||
case MethodReturnKind.Void:
|
||||
{
|
||||
var action = Expression.Lambda<Action<object, object[]>>(body, instance, parameters).Compile();
|
||||
return (_instance, _parameters) =>
|
||||
{
|
||||
action.Invoke(_instance, _parameters);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
var bodyCast = Expression.Convert(body, typeof(object));
|
||||
return Expression.Lambda<Func<object, object[], object>>(bodyCast, instance, parameters).Compile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
36
src/TouchSocket.Core/Reflection/IDynamicMethodInfo.cs
Normal file
36
src/TouchSocket.Core/Reflection/IDynamicMethodInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
public interface IDynamicMethodInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 真实返回值类型。
|
||||
/// <para>当方法为void或task时,为null</para>
|
||||
/// <para>当方法为task泛型时,为泛型元素类型</para>
|
||||
/// </summary>
|
||||
Type RealReturnType { get;}
|
||||
|
||||
/// <summary>
|
||||
/// 返回值的Task类型。
|
||||
/// </summary>
|
||||
MethodReturnKind ReturnKind { get;}
|
||||
|
||||
object Invoke(object instance, object[] parameters);
|
||||
Task<object> GetResultAsync(object result);
|
||||
}
|
||||
190
src/TouchSocket.Core/Reflection/ILDynamicMethodInfo.cs
Normal file
190
src/TouchSocket.Core/Reflection/ILDynamicMethodInfo.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
internal class ILDynamicMethodInfo : DynamicMethodInfoBase
|
||||
{
|
||||
private Func<object, object[], object> m_func;
|
||||
public ILDynamicMethodInfo(MethodInfo method) : base(method)
|
||||
{
|
||||
m_func = CreateILInvoker(method);
|
||||
}
|
||||
|
||||
public override object Invoke(object instance, object[] parameters)
|
||||
{
|
||||
return m_func(instance, parameters);
|
||||
}
|
||||
|
||||
protected static Func<object, object[], object> CreateILInvoker(MethodInfo methodInfo)
|
||||
{
|
||||
var dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[])
|
||||
}, methodInfo.DeclaringType.Module);
|
||||
var il = dynamicMethod.GetILGenerator();
|
||||
var ps = methodInfo.GetParameters();
|
||||
var paramTypes = new Type[ps.Length];
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
paramTypes[i] = ps[i].ParameterType.IsByRef ? ps[i].ParameterType.GetElementType() : ps[i].ParameterType;
|
||||
}
|
||||
var locals = new LocalBuilder[paramTypes.Length];
|
||||
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
locals[i] = il.DeclareLocal(paramTypes[i], true);
|
||||
}
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
EmitFastInt(il, i);
|
||||
il.Emit(OpCodes.Ldelem_Ref);
|
||||
EmitCastToReference(il, paramTypes[i]);
|
||||
il.Emit(OpCodes.Stloc, locals[i]);
|
||||
}
|
||||
if (!methodInfo.IsStatic)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
}
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
if (ps[i].ParameterType.IsByRef)
|
||||
{
|
||||
il.Emit(OpCodes.Ldloca_S, locals[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldloc, locals[i]);
|
||||
}
|
||||
}
|
||||
if (methodInfo.IsStatic)
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, methodInfo, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.EmitCall(OpCodes.Callvirt, methodInfo, null);
|
||||
}
|
||||
|
||||
if (methodInfo.ReturnType == typeof(void))
|
||||
{
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBoxIfNeeded(il, methodInfo.ReturnType);
|
||||
}
|
||||
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
if (ps[i].ParameterType.IsByRef)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
EmitFastInt(il, i);
|
||||
il.Emit(OpCodes.Ldloc, locals[i]);
|
||||
if (locals[i].LocalType.IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Box, locals[i].LocalType);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Stelem_Ref);
|
||||
}
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ret);
|
||||
var invoker = (Func<object, object[], object>)dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>));
|
||||
return invoker;
|
||||
}
|
||||
|
||||
private static void EmitBoxIfNeeded(ILGenerator il, System.Type type)
|
||||
{
|
||||
if (type.IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Box, type);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitCastToReference(ILGenerator il, System.Type type)
|
||||
{
|
||||
if (type.IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Unbox_Any, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Castclass, type);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFastInt(ILGenerator il, int value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case -1:
|
||||
il.Emit(OpCodes.Ldc_I4_M1);
|
||||
return;
|
||||
|
||||
case 0:
|
||||
il.Emit(OpCodes.Ldc_I4_0);
|
||||
return;
|
||||
|
||||
case 1:
|
||||
il.Emit(OpCodes.Ldc_I4_1);
|
||||
return;
|
||||
|
||||
case 2:
|
||||
il.Emit(OpCodes.Ldc_I4_2);
|
||||
return;
|
||||
|
||||
case 3:
|
||||
il.Emit(OpCodes.Ldc_I4_3);
|
||||
return;
|
||||
|
||||
case 4:
|
||||
il.Emit(OpCodes.Ldc_I4_4);
|
||||
return;
|
||||
|
||||
case 5:
|
||||
il.Emit(OpCodes.Ldc_I4_5);
|
||||
return;
|
||||
|
||||
case 6:
|
||||
il.Emit(OpCodes.Ldc_I4_6);
|
||||
return;
|
||||
|
||||
case 7:
|
||||
il.Emit(OpCodes.Ldc_I4_7);
|
||||
return;
|
||||
|
||||
case 8:
|
||||
il.Emit(OpCodes.Ldc_I4_8);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value > -129 && value < 128)
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I4_S, (SByte)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I4, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public class MemberAccessor : IMemberAccessor
|
||||
/// 动态成员访问器
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
public MemberAccessor(Type type)
|
||||
public MemberAccessor([DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields| DynamicallyAccessedMemberTypes.PublicProperties)]Type type)
|
||||
{
|
||||
this.Type = type;
|
||||
this.OnGetFieldInfos = (t) => { return t.GetFields(); };
|
||||
|
||||
@@ -16,171 +16,103 @@ using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 一个动态调用方法
|
||||
/// 动态方法调用器。
|
||||
/// </summary>
|
||||
public class Method
|
||||
{
|
||||
private const string GeneratorTypeNamespace = "TouchSocket.Core.__Internals";
|
||||
private readonly IDynamicMethodInfo m_dynamicMethodInfo;
|
||||
private readonly MethodInfo m_info;
|
||||
private Func<object, object[], object> m_invoker;
|
||||
|
||||
private const string m_generatorTypeNamespace = "TouchSocket.Core.__Internals";
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个动态调用方法
|
||||
/// 使用指定的方法信息和动态方法信息初始化<see cref="Method"/>类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="method">方法信息</param>
|
||||
/// <param name="dynamicBuilderType">指定构建的类型</param>
|
||||
/// <param name="method">关于要表示的方法的元数据信息。不可能 <see langword="null"/>.</param>
|
||||
/// <param name="dynamicMethodInfo">与该方法相关联的动态方法信息。不可能 <see langword="null"/>.</param>
|
||||
public Method(MethodInfo method, IDynamicMethodInfo dynamicMethodInfo)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentNullExceptionIf(dynamicMethodInfo, nameof(dynamicMethodInfo));
|
||||
this.m_info = ThrowHelper.ThrowArgumentNullExceptionIf(method, nameof(method));
|
||||
this.m_dynamicMethodInfo = dynamicMethodInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造方法,初始化 Method 实例。
|
||||
/// </summary>
|
||||
/// <param name="method">目标方法信息。</param>
|
||||
/// <param name="dynamicBuilderType">指定动态构建类型。</param>
|
||||
public Method(MethodInfo method, DynamicBuilderType? dynamicBuilderType = default)
|
||||
{
|
||||
this.m_info = ThrowHelper.ThrowArgumentNullExceptionIf(method, nameof(method));
|
||||
this.Name = method.Name;
|
||||
|
||||
if (method.ReturnType == typeof(Task))
|
||||
{
|
||||
this.HasReturn = false;
|
||||
this.TaskType = TaskReturnType.Task;
|
||||
}
|
||||
else if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
this.HasReturn = true;
|
||||
this.ReturnType = method.ReturnType.GetGenericArguments()[0];
|
||||
this.TaskType = TaskReturnType.TaskObject;
|
||||
}
|
||||
else if (method.ReturnType == typeof(void))
|
||||
{
|
||||
this.HasReturn = false;
|
||||
this.TaskType = TaskReturnType.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.HasReturn = true;
|
||||
this.TaskType = TaskReturnType.None;
|
||||
this.ReturnType = method.ReturnType;
|
||||
}
|
||||
|
||||
if (dynamicBuilderType.HasValue)
|
||||
{
|
||||
switch (dynamicBuilderType.Value)
|
||||
{
|
||||
case DynamicBuilderType.IL:
|
||||
if (!this.CreateInvokeFromIL())
|
||||
{
|
||||
ThrowHelper.ThrowNotSupportedException($"当前环境不支持{dynamicBuilderType.Value}");
|
||||
if (!GlobalEnvironment.IsDynamicCodeSupported)
|
||||
{
|
||||
ThrowHelper.ThrowNotSupportedException($"当前环境不支持{dynamicBuilderType.Value}");
|
||||
}
|
||||
this.m_dynamicMethodInfo = new ILDynamicMethodInfo(method);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DynamicBuilderType.Expression:
|
||||
if (!this.CreateInvokeFromExpression())
|
||||
{
|
||||
ThrowHelper.ThrowNotSupportedException($"当前环境不支持{dynamicBuilderType.Value}");
|
||||
}
|
||||
this.m_dynamicMethodInfo = new ExpressionDynamicMethodInfo(method);
|
||||
break;
|
||||
|
||||
case DynamicBuilderType.Reflect:
|
||||
this.m_dynamicMethodInfo = new ReflectDynamicMethodInfo(method);
|
||||
break;
|
||||
|
||||
case DynamicBuilderType.SourceGenerator:
|
||||
if (!this.CreateInvokeFromSG())
|
||||
{
|
||||
ThrowHelper.ThrowNotSupportedException($"当前环境不支持{dynamicBuilderType.Value}");
|
||||
}
|
||||
this.m_dynamicMethodInfo = CreateDynamicMethodInfoFromSG();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//RuntimeFeature
|
||||
this.CreateInvokeFromSG();
|
||||
this.CreateInvokeFromExpression();
|
||||
this.CreateInvokeFromIL();
|
||||
|
||||
this.DynamicBuilderType = dynamicBuilderType.Value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.m_invoker == null)
|
||||
this.m_dynamicMethodInfo = this.CreateDynamicMethodInfoFromSG();
|
||||
if (this.m_dynamicMethodInfo != null)
|
||||
{
|
||||
this.DynamicBuilderType = DynamicBuilderType.Reflect;
|
||||
this.DynamicBuilderType = DynamicBuilderType.SourceGenerator;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.m_dynamicMethodInfo = new ExpressionDynamicMethodInfo(method);
|
||||
this.DynamicBuilderType = DynamicBuilderType.Expression;
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
this.m_dynamicMethodInfo = new ReflectDynamicMethodInfo(method);
|
||||
this.DynamicBuilderType = DynamicBuilderType.Reflect;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个动态调用方法
|
||||
/// 初始化一个动态调用方法。
|
||||
/// </summary>
|
||||
/// <param name="targetType">目标类型</param>
|
||||
/// <param name="methodName">目标方法</param>
|
||||
/// <param name="dynamicBuilderType">指定构建的类型</param>
|
||||
public Method([DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType,string methodName, DynamicBuilderType? dynamicBuilderType = default)
|
||||
:this(targetType.GetMethod(methodName),dynamicBuilderType)
|
||||
/// <param name="targetType">目标类型。</param>
|
||||
/// <param name="methodName">目标方法名。</param>
|
||||
/// <param name="dynamicBuilderType">指定构建的类型。</param>
|
||||
public Method([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type targetType, string methodName, DynamicBuilderType? dynamicBuilderType = default)
|
||||
: this(targetType.GetMethod(methodName), dynamicBuilderType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
private bool CreateInvokeFromIL()
|
||||
{
|
||||
if (this.m_invoker != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
this.m_invoker = CreateILInvoker(this.Info);
|
||||
this.DynamicBuilderType = DynamicBuilderType.IL;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool CreateInvokeFromExpression()
|
||||
{
|
||||
if (this.m_invoker != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
this.m_invoker = this.CreateExpressionInvoker(this.Info);
|
||||
this.DynamicBuilderType = DynamicBuilderType.Expression;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CreateInvokeFromSG()
|
||||
{
|
||||
if (this.m_invoker != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var typeName = $"{m_generatorTypeNamespace}.__{StringExtension.MakeIdentifier(this.Info.DeclaringType.FullName)}MethodExtension";
|
||||
|
||||
var type = this.Info.DeclaringType.Assembly.GetType(typeName);
|
||||
if (type == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var methodName = $"{this.Info.GetDeterminantName()}Func";
|
||||
var property = type.GetProperty(methodName, BindingFlags.Public | BindingFlags.Static);
|
||||
if (property == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.m_invoker = (Func<object, object[], object>)property.GetValue(null);
|
||||
if (this.m_invoker == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.DynamicBuilderType = DynamicBuilderType.SourceGenerator;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -191,382 +123,117 @@ public class Method
|
||||
/// <summary>
|
||||
/// 是否具有返回值。当返回值为Task时,也会认为没有返回值。
|
||||
/// </summary>
|
||||
public bool HasReturn { get; private set; }
|
||||
public bool HasReturn => this.RealReturnType!=null;
|
||||
|
||||
/// <summary>
|
||||
/// 方法信息
|
||||
/// 方法信息。
|
||||
/// </summary>
|
||||
public MethodInfo Info => this.m_info;
|
||||
|
||||
/// <summary>
|
||||
/// 获取方法名
|
||||
/// 获取一个值,该值指示该方法的返回类型是否支持等待。
|
||||
/// </summary>
|
||||
public string Name { get; protected set; }
|
||||
public bool IsAwaitable => this.ReturnKind == MethodReturnKind.Awaitable || this.ReturnKind == MethodReturnKind.AwaitableObject;
|
||||
|
||||
/// <summary>
|
||||
/// 返回值类型。
|
||||
/// <para>当方法为void或task时,为null</para>
|
||||
/// <para>当方法为task泛型时,为泛型元素类型</para>
|
||||
/// 获取方法名。
|
||||
/// </summary>
|
||||
public Type ReturnType { get; private set; }
|
||||
public string Name => this.m_info.Name;
|
||||
|
||||
/// <summary>
|
||||
/// 真实返回值类型。
|
||||
/// <para>当方法为void或task时,为null。</para>
|
||||
/// <para>当方法为task泛型时,为泛型元素类型。</para>
|
||||
/// </summary>
|
||||
public Type RealReturnType => this.m_dynamicMethodInfo.RealReturnType;
|
||||
|
||||
/// <summary>
|
||||
/// 返回值的Task类型。
|
||||
/// </summary>
|
||||
public TaskReturnType TaskType { get; private set; }
|
||||
public MethodReturnKind ReturnKind => this.m_dynamicMethodInfo.ReturnKind;
|
||||
|
||||
#region Invoke
|
||||
|
||||
/// <summary>
|
||||
/// 执行方法。
|
||||
/// 同步调用方法。
|
||||
/// </summary>
|
||||
/// <param name="instance">实例</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <returns></returns>
|
||||
/// <param name="instance">实例对象。</param>
|
||||
/// <param name="parameters">参数数组。</param>
|
||||
/// <returns>方法返回值。</returns>
|
||||
public object Invoke(object instance, params object[] parameters)
|
||||
{
|
||||
if (this.m_invoker == null)
|
||||
{
|
||||
return this.Info.Invoke(instance, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.m_invoker.Invoke(instance, parameters);
|
||||
}
|
||||
return this.m_dynamicMethodInfo.Invoke(instance, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步执行方法。
|
||||
/// 异步调用方法,返回指定类型结果。
|
||||
/// </summary>
|
||||
/// <param name="instance">实例</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <returns>返回一个表示异步操作的任务。</returns>
|
||||
public Task InvokeAsync(object instance, params object[] parameters)
|
||||
/// <typeparam name="TResult">结果类型。</typeparam>
|
||||
/// <param name="instance">实例对象。</param>
|
||||
/// <param name="parameters">参数数组。</param>
|
||||
/// <returns>异步任务,包含方法返回值。</returns>
|
||||
public async Task<TResult> InvokeAsync<TResult>(object instance, params object[] parameters)
|
||||
{
|
||||
switch (this.TaskType)
|
||||
{
|
||||
case TaskReturnType.None:
|
||||
{
|
||||
throw new Exception("该方法不包含Task。");
|
||||
}
|
||||
case TaskReturnType.Task:
|
||||
{
|
||||
object re;
|
||||
if (this.m_invoker == null)
|
||||
{
|
||||
re = this.Info.Invoke(instance, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
re = this.m_invoker.Invoke(instance, parameters);
|
||||
}
|
||||
return (TResult)await this.InvokeAsync(instance, parameters).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
}
|
||||
|
||||
return (Task)re;
|
||||
}
|
||||
case TaskReturnType.TaskObject:
|
||||
/// <summary>
|
||||
/// 异步调用方法。
|
||||
/// </summary>
|
||||
/// <param name="instance">实例对象。</param>
|
||||
/// <param name="parameters">参数数组。</param>
|
||||
/// <returns>异步任务,包含方法返回值。</returns>
|
||||
public async Task<object> InvokeAsync(object instance, params object[] parameters)
|
||||
{
|
||||
switch (this.ReturnKind)
|
||||
{
|
||||
case MethodReturnKind.Void:
|
||||
this.Invoke(instance, parameters);
|
||||
return default;
|
||||
|
||||
case MethodReturnKind.Object:
|
||||
return this.Invoke(instance, parameters);
|
||||
|
||||
case MethodReturnKind.Awaitable:
|
||||
{
|
||||
object re;
|
||||
if (this.m_invoker == null)
|
||||
{
|
||||
re = this.Info.Invoke(instance, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
re = this.m_invoker.Invoke(instance, parameters);
|
||||
}
|
||||
return (Task)re;
|
||||
var rawResult = this.Invoke(instance, parameters);
|
||||
await this.m_dynamicMethodInfo.GetResultAsync(rawResult).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
return default;
|
||||
}
|
||||
case MethodReturnKind.AwaitableObject:
|
||||
{
|
||||
var rawResult = this.Invoke(instance, parameters);
|
||||
return (await this.m_dynamicMethodInfo.GetResultAsync(rawResult).ConfigureAwait(EasyTask.ContinueOnCapturedContext));
|
||||
}
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用异步结果
|
||||
/// </summary>
|
||||
/// <param name="instance"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
public Task<TResult> InvokeAsync<TResult>(object instance, params object[] parameters)
|
||||
{
|
||||
switch (this.TaskType)
|
||||
{
|
||||
case TaskReturnType.None:
|
||||
{
|
||||
throw new Exception($"{this.Info}不包含任何Task<>返回值。他可能是个同步函数。");
|
||||
}
|
||||
case TaskReturnType.Task:
|
||||
{
|
||||
throw new Exception($"{this.Info}不包含任何可等待的Task<>返回值。");
|
||||
}
|
||||
case TaskReturnType.TaskObject:
|
||||
{
|
||||
object re;
|
||||
if (this.m_invoker == null)
|
||||
{
|
||||
re = this.Info.Invoke(instance, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
re = this.m_invoker.Invoke(instance, parameters);
|
||||
}
|
||||
return (Task<TResult>)re;
|
||||
}
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行方法。
|
||||
/// <para>当方法为void或task时,会异常</para>
|
||||
/// <para>当方法为task泛型时,会await后的值</para>
|
||||
/// <para>支持调用方为UI主线程。</para>
|
||||
/// </summary>
|
||||
/// <param name="instance">实例</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <returns></returns>
|
||||
public async Task<object> InvokeObjectAsync(object instance, params object[] parameters)
|
||||
{
|
||||
switch (this.TaskType)
|
||||
{
|
||||
case TaskReturnType.None:
|
||||
{
|
||||
throw new Exception($"{this.Info}不包含任何Task<>返回值。他可能是个同步函数。");
|
||||
}
|
||||
case TaskReturnType.Task:
|
||||
{
|
||||
throw new Exception($"{this.Info}不包含任何可等待的Task<>返回值。");
|
||||
}
|
||||
case TaskReturnType.TaskObject:
|
||||
{
|
||||
Task task;
|
||||
if (this.m_invoker == null)
|
||||
{
|
||||
task = (Task)this.Info.Invoke(instance, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = (Task)this.m_invoker.Invoke(instance, parameters);
|
||||
}
|
||||
|
||||
await task.ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
return DynamicMethodMemberAccessor.Default.GetValue(task, "Result");
|
||||
}
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建IL调用
|
||||
/// </summary>
|
||||
/// <param name="methodInfo"></param>
|
||||
/// <returns></returns>
|
||||
protected static Func<object, object[], object> CreateILInvoker(MethodInfo methodInfo)
|
||||
{
|
||||
var dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[])
|
||||
}, methodInfo.DeclaringType.Module);
|
||||
var il = dynamicMethod.GetILGenerator();
|
||||
var ps = methodInfo.GetParameters();
|
||||
var paramTypes = new Type[ps.Length];
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
paramTypes[i] = ps[i].ParameterType.IsByRef ? ps[i].ParameterType.GetElementType() : ps[i].ParameterType;
|
||||
}
|
||||
var locals = new LocalBuilder[paramTypes.Length];
|
||||
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
locals[i] = il.DeclareLocal(paramTypes[i], true);
|
||||
}
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
EmitFastInt(il, i);
|
||||
il.Emit(OpCodes.Ldelem_Ref);
|
||||
EmitCastToReference(il, paramTypes[i]);
|
||||
il.Emit(OpCodes.Stloc, locals[i]);
|
||||
}
|
||||
if (!methodInfo.IsStatic)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
}
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
if (ps[i].ParameterType.IsByRef)
|
||||
{
|
||||
il.Emit(OpCodes.Ldloca_S, locals[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldloc, locals[i]);
|
||||
}
|
||||
}
|
||||
if (methodInfo.IsStatic)
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, methodInfo, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.EmitCall(OpCodes.Callvirt, methodInfo, null);
|
||||
}
|
||||
|
||||
if (methodInfo.ReturnType == typeof(void))
|
||||
{
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBoxIfNeeded(il, methodInfo.ReturnType);
|
||||
}
|
||||
|
||||
for (var i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
if (ps[i].ParameterType.IsByRef)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
EmitFastInt(il, i);
|
||||
il.Emit(OpCodes.Ldloc, locals[i]);
|
||||
if (locals[i].LocalType.IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Box, locals[i].LocalType);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Stelem_Ref);
|
||||
}
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ret);
|
||||
var invoker= (Func<object, object[], object>)dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>));
|
||||
return invoker;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建表达式树调用
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <returns></returns>
|
||||
protected Func<object, object[], object> CreateExpressionInvoker(MethodInfo method)
|
||||
{
|
||||
var instance = Expression.Parameter(typeof(object), "instance");
|
||||
var parameters = Expression.Parameter(typeof(object[]), "parameters");
|
||||
|
||||
var instanceCast = method.IsStatic ? null : Expression.Convert(instance, method.DeclaringType);
|
||||
var parametersCast = method.GetParameters().Select((p, i) =>
|
||||
{
|
||||
var parameter = Expression.ArrayIndex(parameters, Expression.Constant(i));
|
||||
return Expression.Convert(parameter, p.ParameterType);
|
||||
});
|
||||
|
||||
var body = Expression.Call(instanceCast, method, parametersCast);
|
||||
|
||||
if (method.ReturnType == typeof(Task))
|
||||
{
|
||||
this.HasReturn = false;
|
||||
this.TaskType = TaskReturnType.Task;
|
||||
var bodyCast = Expression.Convert(body, typeof(object));
|
||||
return Expression.Lambda<Func<object, object[], object>>(bodyCast, instance, parameters).Compile();
|
||||
}
|
||||
else if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
this.TaskType = TaskReturnType.TaskObject;
|
||||
this.HasReturn = true;
|
||||
this.ReturnType = method.ReturnType.GetGenericArguments()[0];
|
||||
var bodyCast = Expression.Convert(body, typeof(object));
|
||||
return Expression.Lambda<Func<object, object[], object>>(bodyCast, instance, parameters).Compile();
|
||||
}
|
||||
else if (method.ReturnType == typeof(void))
|
||||
{
|
||||
this.HasReturn = false;
|
||||
this.TaskType = TaskReturnType.None;
|
||||
var action = Expression.Lambda<Action<object, object[]>>(body, instance, parameters).Compile();
|
||||
return (_instance, _parameters) =>
|
||||
{
|
||||
action.Invoke(_instance, _parameters);
|
||||
ThrowHelper.ThrowInvalidEnumArgumentException(this.ReturnKind);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
this.HasReturn = true;
|
||||
this.TaskType = TaskReturnType.None;
|
||||
this.ReturnType = method.ReturnType;
|
||||
var bodyCast = Expression.Convert(body, typeof(object));
|
||||
return Expression.Lambda<Func<object, object[], object>>(bodyCast, instance, parameters).Compile();
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitBoxIfNeeded(ILGenerator il, System.Type type)
|
||||
#endregion Invoke
|
||||
|
||||
/// <summary>
|
||||
/// 通过源生成器创建动态方法信息。
|
||||
/// </summary>
|
||||
/// <returns>动态方法信息接口。</returns>
|
||||
private IDynamicMethodInfo CreateDynamicMethodInfoFromSG()
|
||||
{
|
||||
if (type.IsValueType)
|
||||
var typeName = $"{GeneratorTypeNamespace}.__{StringExtension.MakeIdentifier(this.Info.DeclaringType.FullName)}MethodExtension";
|
||||
|
||||
var type = this.Info.DeclaringType.Assembly.GetType(typeName);
|
||||
if (type == null)
|
||||
{
|
||||
il.Emit(OpCodes.Box, type);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitCastToReference(ILGenerator il, System.Type type)
|
||||
{
|
||||
if (type.IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Unbox_Any, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Castclass, type);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFastInt(ILGenerator il, int value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case -1:
|
||||
il.Emit(OpCodes.Ldc_I4_M1);
|
||||
return;
|
||||
|
||||
case 0:
|
||||
il.Emit(OpCodes.Ldc_I4_0);
|
||||
return;
|
||||
|
||||
case 1:
|
||||
il.Emit(OpCodes.Ldc_I4_1);
|
||||
return;
|
||||
|
||||
case 2:
|
||||
il.Emit(OpCodes.Ldc_I4_2);
|
||||
return;
|
||||
|
||||
case 3:
|
||||
il.Emit(OpCodes.Ldc_I4_3);
|
||||
return;
|
||||
|
||||
case 4:
|
||||
il.Emit(OpCodes.Ldc_I4_4);
|
||||
return;
|
||||
|
||||
case 5:
|
||||
il.Emit(OpCodes.Ldc_I4_5);
|
||||
return;
|
||||
|
||||
case 6:
|
||||
il.Emit(OpCodes.Ldc_I4_6);
|
||||
return;
|
||||
|
||||
case 7:
|
||||
il.Emit(OpCodes.Ldc_I4_7);
|
||||
return;
|
||||
|
||||
case 8:
|
||||
il.Emit(OpCodes.Ldc_I4_8);
|
||||
return;
|
||||
return default;
|
||||
}
|
||||
|
||||
if (value > -129 && value < 128)
|
||||
var methodName = $"{this.Info.GetDeterminantName()}ClassProperty";
|
||||
var property = type.GetProperty(methodName, BindingFlags.Public | BindingFlags.Static);
|
||||
if (property == null)
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I4_S, (SByte)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I4, value);
|
||||
return default;
|
||||
}
|
||||
|
||||
return (IDynamicMethodInfo)property.GetValue(null);
|
||||
}
|
||||
}
|
||||
@@ -12,23 +12,29 @@
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Task类型
|
||||
/// 表示方法的返回类型。
|
||||
/// </summary>
|
||||
public enum TaskReturnType
|
||||
public enum MethodReturnKind
|
||||
{
|
||||
/// <summary>
|
||||
/// 没有Task
|
||||
/// 方法没有返回值。
|
||||
/// </summary>
|
||||
None,
|
||||
Void,
|
||||
|
||||
/// <summary>
|
||||
/// 仅返回Task
|
||||
/// 方法返回一个对象。
|
||||
/// </summary>
|
||||
Task,
|
||||
Object,
|
||||
|
||||
/// <summary>
|
||||
/// 返回Task的值
|
||||
/// 方法返回一个可等待的任务。
|
||||
/// </summary>
|
||||
TaskObject
|
||||
Awaitable,
|
||||
|
||||
/// <summary>
|
||||
/// 方法返回一个可等待的任务,并且任务有返回值。
|
||||
/// </summary>
|
||||
AwaitableObject
|
||||
}
|
||||
34
src/TouchSocket.Core/Reflection/ReflectDynamicMethodInfo.cs
Normal file
34
src/TouchSocket.Core/Reflection/ReflectDynamicMethodInfo.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
internal class ReflectDynamicMethodInfo : DynamicMethodInfoBase
|
||||
{
|
||||
private readonly MethodInfo m_method;
|
||||
|
||||
public ReflectDynamicMethodInfo(MethodInfo method) : base(method)
|
||||
{
|
||||
this.m_method = method;
|
||||
}
|
||||
|
||||
public override object Invoke(object instance, object[] parameters)
|
||||
{
|
||||
return m_method.Invoke(instance, parameters);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,10 @@
|
||||
<None Include="..\TouchSocket.Core.SourceGenerator\bin\$(Configuration)\netstandard2.0\TouchSocket.Core.SourceGenerator.dll" PackagePath="analyzers\dotnet\cs" Pack="true" Visible="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--<ItemGroup Condition="'$(TargetFramework)'=='net45'">
|
||||
<Analyzer Include="..\TouchSocket.Core.SourceGenerator\bin\$(Configuration)\netstandard2.0\TouchSocket.Core.SourceGenerator.dll" />
|
||||
</ItemGroup>-->
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
|
||||
<PackageReference Include="System.Reflection.Emit.ILGeneration" Version="4.7.0" PrivateAssets="All" />
|
||||
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" PrivateAssets="All" />
|
||||
|
||||
@@ -44,14 +44,14 @@ public interface IWaitDataBase<T> : IDisposableObject
|
||||
/// <summary>
|
||||
/// 使等待的线程继续执行。
|
||||
/// </summary>
|
||||
/// <returns>如果操作成功,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果操作成功,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
bool Set();
|
||||
|
||||
/// <summary>
|
||||
/// 使等待的线程继续执行,并设置等待结果。
|
||||
/// </summary>
|
||||
/// <param name="waitResult">等待结果。</param>
|
||||
/// <returns>如果操作成功,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果操作成功,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
bool Set(T waitResult);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1067,7 +1067,7 @@ public abstract class DmtpActor : DisposableObject, IDmtpActor
|
||||
channel = null;
|
||||
return false;
|
||||
}
|
||||
channelOut.SetUsing();
|
||||
channelOut.MakeUsing();
|
||||
channel = channelOut;
|
||||
return true;
|
||||
}
|
||||
@@ -1133,7 +1133,7 @@ public abstract class DmtpActor : DisposableObject, IDmtpActor
|
||||
{
|
||||
var channel = new InternalChannel(this, targetId, result.Metadata);
|
||||
channel.SetId(result.ChannelId);
|
||||
channel.SetUsing();
|
||||
channel.MakeUsing();
|
||||
if (this.m_userChannels.TryAdd(result.ChannelId, channel))
|
||||
{
|
||||
return channel;
|
||||
|
||||
@@ -68,7 +68,7 @@ public interface IDmtpActor : IDisposableObject, IOnlineClient, IClosableClient,
|
||||
/// 判断指定Id的通道是否已经存在
|
||||
/// </summary>
|
||||
/// <param name="id">要判断的通道Id</param>
|
||||
/// <returns>如果通道存在返回true,否则返回false</returns>
|
||||
/// <returns>如果通道存在返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
bool ChannelExisted(int id);
|
||||
|
||||
/// <summary>
|
||||
@@ -108,7 +108,7 @@ public interface IDmtpActor : IDisposableObject, IOnlineClient, IClosableClient,
|
||||
/// </summary>
|
||||
/// <param name="id">要订阅的通道的标识符。</param>
|
||||
/// <param name="channel">订阅的通道对象,成功时返回此参数。</param>
|
||||
/// <returns>如果订阅成功则返回true;如果通道不存在或发生错误则返回false。</returns>
|
||||
/// <returns>如果订阅成功则返回<see langword="true"/>;如果通道不存在或发生错误则返回<see langword="false"/>。</returns>
|
||||
bool TrySubscribeChannel(int id, out IDmtpChannel channel);
|
||||
|
||||
#endregion IDmtpChannel
|
||||
|
||||
@@ -87,14 +87,14 @@ public partial interface IDmtpChannel : IDisposable, IEnumerable<ByteBlock>
|
||||
/// </summary>
|
||||
/// <param name="operationMes">可选参数,用于提供取消操作的详细信息</param>
|
||||
/// <returns>返回一个Task对象,表示异步取消操作的完成</returns>
|
||||
Task CancelAsync(string operationMes = null);
|
||||
Task<Result> CancelAsync(string operationMes = null);
|
||||
|
||||
/// <summary>
|
||||
/// 异步完成操作
|
||||
/// </summary>
|
||||
/// <param name="operationMes">操作信息,可选参数,默认为null</param>
|
||||
/// <returns>返回一个Task对象,表示异步操作的完成</returns>
|
||||
Task CompleteAsync(string operationMes = null);
|
||||
Task<Result> CompleteAsync(string operationMes = null);
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前的有效数据。在使用之后,请进行显式的<see cref="IDisposable.Dispose"/>调用。
|
||||
@@ -107,7 +107,7 @@ public partial interface IDmtpChannel : IDisposable, IEnumerable<ByteBlock>
|
||||
/// </summary>
|
||||
/// <param name="operationMes"></param>
|
||||
/// <returns></returns>
|
||||
Task HoldOnAsync(string operationMes = null);
|
||||
Task<Result> HoldOnAsync(string operationMes = null);
|
||||
|
||||
/// <summary>
|
||||
/// 转向下个元素
|
||||
|
||||
@@ -22,7 +22,7 @@ using TouchSocket.Core;
|
||||
namespace TouchSocket.Dmtp;
|
||||
|
||||
[DebuggerDisplay("Id={Id},Status={Status}")]
|
||||
internal sealed partial class InternalChannel : DisposableObject, IDmtpChannel
|
||||
internal sealed partial class InternalChannel : SafetyDisposableObject, IDmtpChannel
|
||||
{
|
||||
private readonly DmtpActor m_actor;
|
||||
private readonly ConcurrentQueue<ChannelPackage> m_dataQueue;
|
||||
@@ -94,11 +94,11 @@ internal sealed partial class InternalChannel : DisposableObject, IDmtpChannel
|
||||
|
||||
#region 操作
|
||||
|
||||
public async Task CancelAsync(string operationMes = null)
|
||||
public async Task<Result> CancelAsync(string operationMes = null)
|
||||
{
|
||||
if ((byte)this.Status > 3)
|
||||
{
|
||||
return;
|
||||
return Result.Success;
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -114,53 +114,73 @@ internal sealed partial class InternalChannel : DisposableObject, IDmtpChannel
|
||||
};
|
||||
await this.m_actor.SendChannelPackageAsync(channelPackage).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
this.m_lastOperationTime = DateTimeOffset.UtcNow;
|
||||
return Result.Success;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.FromException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CompleteAsync(string operationMes = null)
|
||||
public async Task<Result> CompleteAsync(string operationMes = null)
|
||||
{
|
||||
if ((byte)this.Status > 3)
|
||||
{
|
||||
return;
|
||||
return Result.Success;
|
||||
}
|
||||
try
|
||||
{
|
||||
this.RequestComplete(true);
|
||||
var channelPackage = new ChannelPackage()
|
||||
{
|
||||
ChannelId = this.Id,
|
||||
RunNow = true,
|
||||
DataType = ChannelDataType.CompleteOrder,
|
||||
Message = operationMes,
|
||||
SourceId = this.m_actor.Id,
|
||||
TargetId = this.TargetId
|
||||
};
|
||||
await this.m_actor.SendChannelPackageAsync(channelPackage).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
this.m_lastOperationTime = DateTimeOffset.UtcNow;
|
||||
return Result.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.FromException(ex);
|
||||
}
|
||||
|
||||
this.RequestComplete(true);
|
||||
var channelPackage = new ChannelPackage()
|
||||
{
|
||||
ChannelId = this.Id,
|
||||
RunNow = true,
|
||||
DataType = ChannelDataType.CompleteOrder,
|
||||
Message = operationMes,
|
||||
SourceId = this.m_actor.Id,
|
||||
TargetId = this.TargetId
|
||||
};
|
||||
await this.m_actor.SendChannelPackageAsync(channelPackage).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
this.m_lastOperationTime = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public async Task HoldOnAsync(string operationMes = null)
|
||||
public async Task<Result> HoldOnAsync(string operationMes = null)
|
||||
{
|
||||
if ((byte)this.Status > 3)
|
||||
{
|
||||
return;
|
||||
return Result.Success;
|
||||
}
|
||||
var channelPackage = new ChannelPackage()
|
||||
try
|
||||
{
|
||||
ChannelId = this.Id,
|
||||
RunNow = true,
|
||||
DataType = ChannelDataType.HoldOnOrder,
|
||||
Message = operationMes,
|
||||
SourceId = this.m_actor.Id,
|
||||
TargetId = this.TargetId
|
||||
};
|
||||
await this.m_actor.SendChannelPackageAsync(channelPackage).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
this.m_lastOperationTime = DateTimeOffset.UtcNow;
|
||||
var channelPackage = new ChannelPackage()
|
||||
{
|
||||
ChannelId = this.Id,
|
||||
RunNow = true,
|
||||
DataType = ChannelDataType.HoldOnOrder,
|
||||
Message = operationMes,
|
||||
SourceId = this.m_actor.Id,
|
||||
TargetId = this.TargetId
|
||||
};
|
||||
await this.m_actor.SendChannelPackageAsync(channelPackage).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
this.m_lastOperationTime = DateTimeOffset.UtcNow;
|
||||
return Result.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.FromException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
||||
protected override void SafetyDispose(bool disposing)
|
||||
{
|
||||
//不判断disposing,能够让GC也能发送释放指令
|
||||
try
|
||||
@@ -186,9 +206,8 @@ internal sealed partial class InternalChannel : DisposableObject, IDmtpChannel
|
||||
catch
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
|
||||
#endregion 操作
|
||||
|
||||
public ByteBlock GetCurrent()
|
||||
@@ -394,7 +413,7 @@ internal sealed partial class InternalChannel : DisposableObject, IDmtpChannel
|
||||
this.Id = id;
|
||||
}
|
||||
|
||||
internal void SetUsing()
|
||||
internal void MakeUsing()
|
||||
{
|
||||
this.Using = true;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public readonly struct RouteType
|
||||
/// </summary>
|
||||
/// <param name="a">第一个RouteType对象</param>
|
||||
/// <param name="b">第二个RouteType对象</param>
|
||||
/// <returns>如果两个对象相等返回true,否则返回false</returns>
|
||||
/// <returns>如果两个对象相等返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
public static bool operator ==(RouteType a, RouteType b)
|
||||
{
|
||||
return a.m_value == b.m_value;
|
||||
@@ -55,7 +55,7 @@ public readonly struct RouteType
|
||||
/// </summary>
|
||||
/// <param name="a">第一个RouteType对象</param>
|
||||
/// <param name="b">第二个RouteType对象</param>
|
||||
/// <returns>如果两个对象不相等返回true,否则返回false</returns>
|
||||
/// <returns>如果两个对象不相等返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
public static bool operator !=(RouteType a, RouteType b)
|
||||
{
|
||||
return a.m_value != b.m_value;
|
||||
@@ -65,7 +65,7 @@ public readonly struct RouteType
|
||||
/// 重写Equals方法,用于比较两个RouteType对象是否相等
|
||||
/// </summary>
|
||||
/// <param name="obj">要比较的对象</param>
|
||||
/// <returns>如果对象相等返回true,否则返回false</returns>
|
||||
/// <returns>如果对象相等返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is RouteType type && this == type;
|
||||
|
||||
@@ -58,24 +58,28 @@ public static class DmtpActorExtension
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.CreateChannelAsync(Metadata)"/>
|
||||
[AsyncToSyncWarning]
|
||||
public static IDmtpChannel CreateChannel(this IDmtpActorObject client, Metadata metadata = default)
|
||||
{
|
||||
return client.DmtpActor.CreateChannelAsync(metadata).GetFalseAwaitResult();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.CreateChannelAsync(int, Metadata)"/>
|
||||
[AsyncToSyncWarning]
|
||||
public static IDmtpChannel CreateChannel(this IDmtpActorObject client, int id, Metadata metadata = default)
|
||||
{
|
||||
return client.DmtpActor.CreateChannelAsync(id, metadata).GetFalseAwaitResult();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.CreateChannelAsync(string, int, Metadata)"/>
|
||||
[AsyncToSyncWarning]
|
||||
public static IDmtpChannel CreateChannel(this IDmtpActorObject client, string targetId, int id, Metadata metadata = default)
|
||||
{
|
||||
return client.DmtpActor.CreateChannelAsync(targetId, id, metadata).GetFalseAwaitResult();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.CreateChannelAsync(string, Metadata)"/>
|
||||
[AsyncToSyncWarning]
|
||||
public static IDmtpChannel CreateChannel(this IDmtpActorObject client, string targetId, Metadata metadata = default)
|
||||
{
|
||||
return client.DmtpActor.CreateChannelAsync(targetId, metadata).GetFalseAwaitResult();
|
||||
@@ -144,7 +148,7 @@ public static class DmtpActorExtension
|
||||
/// <returns>返回一个布尔值,表示是否成功发送数据。</returns>
|
||||
public static async Task<bool> TrySendAsync(this IDmtpActorObject client, ushort protocol)
|
||||
{
|
||||
// 尝试发送数据,如果成功则返回true,失败则返回false。
|
||||
// 尝试发送数据,如果成功则返回<see langword="true"/>,失败则返回<see langword="false"/>。
|
||||
try
|
||||
{
|
||||
// 使用空的内存数据发送协议命令。
|
||||
@@ -153,7 +157,7 @@ public static class DmtpActorExtension
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果发送过程中发生异常,则返回false。
|
||||
// 如果发送过程中发生异常,则返回<see langword="false"/>。
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -219,12 +223,12 @@ public static class DmtpActorExtension
|
||||
{
|
||||
// 实际执行发送操作。
|
||||
await SendAsync(client, protocol, package, maxSize).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
// 发送成功,返回true。
|
||||
// 发送成功,返回<see langword="true"/>。
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 发送失败,返回false。
|
||||
// 发送失败,返回<see langword="false"/>。
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -235,10 +239,10 @@ public static class DmtpActorExtension
|
||||
/// <param name="client">要发送包的客户端。</param>
|
||||
/// <param name="protocol">使用的协议。</param>
|
||||
/// <param name="package">要发送的包。</param>
|
||||
/// <returns>如果发送成功,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果发送成功,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public static async Task<bool> TrySendAsync(this IDmtpActorObject client, ushort protocol, IPackage package)
|
||||
{
|
||||
// 尝试发送包,如果成功则返回true,失败则返回false
|
||||
// 尝试发送包,如果成功则返回<see langword="true"/>,失败则返回<see langword="false"/>
|
||||
try
|
||||
{
|
||||
// 实际执行发送操作,64KB是根据业务需求预设的限制
|
||||
|
||||
@@ -68,13 +68,13 @@ public class FileSection : PackageBase
|
||||
/// 判断基本信息是否一致。
|
||||
/// </summary>
|
||||
/// <param name="fileSection">待比较的文件段对象。</param>
|
||||
/// <returns>如果待比较的文件段对象的基本信息与当前对象一致,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果待比较的文件段对象的基本信息与当前对象一致,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public bool Equals(FileSection fileSection)
|
||||
{
|
||||
// 检查待比较的文件段对象是否为null
|
||||
if (fileSection == null)
|
||||
{
|
||||
// 如果是null,直接返回false,因为无法比较
|
||||
// 如果是null,直接返回<see langword="false"/>,因为无法比较
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -21,7 +21,7 @@ public static class TransferTypeExtension
|
||||
/// 表示当前传输类型是否属于<see cref="TransferType.Pull"/>、<see cref="TransferType.SmallPull"/>其中的一种。
|
||||
/// </summary>
|
||||
/// <param name="transferType">要检查的传输类型。</param>
|
||||
/// <returns>如果传输类型是<see cref="TransferType.Pull"/>或<see cref="TransferType.SmallPull"/>,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果传输类型是<see cref="TransferType.Pull"/>或<see cref="TransferType.SmallPull"/>,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public static bool IsPull(this TransferType transferType)
|
||||
{
|
||||
return transferType == TransferType.Pull || transferType == TransferType.SmallPull;
|
||||
|
||||
@@ -49,7 +49,7 @@ public interface IFileResourceController : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="resourceHandle">资源句柄,标识需要释放的文件资源定位器</param>
|
||||
/// <param name="locator">输出参数,返回被释放的文件资源定位器</param>
|
||||
/// <returns>如果成功释放文件资源定位器,则返回true;否则返回false</returns>
|
||||
/// <returns>如果成功释放文件资源定位器,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
bool TryReleaseFileResourceLocator(int resourceHandle, out FileResourceLocator locator);
|
||||
|
||||
/// <summary>
|
||||
@@ -57,7 +57,7 @@ public interface IFileResourceController : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="resourceHandle">文件句柄,用于标识特定的文件资源。</param>
|
||||
/// <param name="fileResourceLocator">输出参数,返回文件的资源定位器。</param>
|
||||
/// <returns>如果成功获取资源定位器,返回true;否则返回false。</returns>
|
||||
/// <returns>如果成功获取资源定位器,返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
bool TryGetFileResourceLocator(int resourceHandle, out FileResourceLocator fileResourceLocator);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -79,7 +79,7 @@ public class HttpRequest : HttpBase
|
||||
/// <summary>
|
||||
/// 保持连接。
|
||||
/// <para>
|
||||
/// 一般的,当是http1.1时,如果没有显式的Connection: close,即返回true。当是http1.0时,如果没有显式的Connection: Keep-Alive,即返回false。
|
||||
/// 一般的,当是http1.1时,如果没有显式的Connection: close,即返回<see langword="true"/>。当是http1.0时,如果没有显式的Connection: Keep-Alive,即返回<see langword="false"/>。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool KeepAlive
|
||||
|
||||
@@ -384,7 +384,7 @@ public static partial class HttpExtensions
|
||||
/// </summary>
|
||||
/// <param name="request">请求对象,用于获取待对比的相对URL。</param>
|
||||
/// <param name="url">待对比的目标URL字符串。</param>
|
||||
/// <returns>如果两个URL都不为null且在忽略大小写的情况下相等,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果两个URL都不为null且在忽略大小写的情况下相等,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public static bool UrlEquals<TRequest>(this TRequest request, string url) where TRequest : HttpRequest
|
||||
{
|
||||
// 检查两个URL是否都不为null,并且在文化无关的大小写不敏感的情况下是否相等
|
||||
@@ -510,7 +510,7 @@ public static partial class HttpExtensions
|
||||
/// 判断当前请求是否为Delete操作
|
||||
/// </summary>
|
||||
/// <param name="request">请求对象,用于检查请求方法</param>
|
||||
/// <returns>如果请求方法为Delete,则返回true;否则返回false</returns>
|
||||
/// <returns>如果请求方法为Delete,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
public static bool IsDelete<TRequest>(this TRequest request) where TRequest : HttpRequest
|
||||
{
|
||||
return request.Method == HttpMethod.Delete;
|
||||
@@ -520,7 +520,7 @@ public static partial class HttpExtensions
|
||||
/// 判断当前请求是否为Get请求
|
||||
/// </summary>
|
||||
/// <param name="request">请求对象,用于检查其请求方法</param>
|
||||
/// <returns>如果请求方法是Get,则返回true;否则返回false</returns>
|
||||
/// <returns>如果请求方法是Get,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
public static bool IsGet<TRequest>(this TRequest request) where TRequest : HttpRequest
|
||||
{
|
||||
return request.Method == HttpMethod.Get;
|
||||
@@ -531,7 +531,7 @@ public static partial class HttpExtensions
|
||||
/// </summary>
|
||||
/// <param name="request">待检查的HTTP请求</param>
|
||||
/// <param name="method">要判断的HTTP方法类型,如"Get"、"Post"</param>
|
||||
/// <returns>如果请求的方法类型与指定的方法一致,则返回true;否则返回false</returns>
|
||||
/// <returns>如果请求的方法类型与指定的方法一致,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
public static bool IsMethod<TRequest>(this TRequest request, string method) where TRequest : HttpRequest
|
||||
{
|
||||
return request.Method == new HttpMethod(method);
|
||||
@@ -541,7 +541,7 @@ public static partial class HttpExtensions
|
||||
/// 判断当前请求是否为Post请求
|
||||
/// </summary>
|
||||
/// <param name="request">请求对象,泛型参数,必须是HttpRequest的子类或实现</param>
|
||||
/// <returns>如果当前请求方法是Post,则返回true;否则返回false</returns>
|
||||
/// <returns>如果当前请求方法是Post,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
public static bool IsPost<TRequest>(this TRequest request) where TRequest : HttpRequest
|
||||
{
|
||||
// 直接比较请求对象的Method属性是否为HttpMethod.Post,以判断是否为Post请求
|
||||
@@ -552,7 +552,7 @@ public static partial class HttpExtensions
|
||||
/// 判断请求是否为PUT方法
|
||||
/// </summary>
|
||||
/// <param name="request">请求对象,类型为HttpRequest的泛型实例</param>
|
||||
/// <returns>如果请求方法为PUT,则返回true;否则返回false</returns>
|
||||
/// <returns>如果请求方法为PUT,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
public static bool IsPut<TRequest>(this TRequest request) where TRequest : HttpRequest
|
||||
{
|
||||
return request.Method == HttpMethod.Put;
|
||||
@@ -566,7 +566,7 @@ public static partial class HttpExtensions
|
||||
/// 判断请求是否接受Gzip压缩。
|
||||
/// </summary>
|
||||
/// <param name="request">请求对象,用于获取请求的接受编码。</param>
|
||||
/// <returns>如果请求接受Gzip压缩,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果请求接受Gzip压缩,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public static bool IsAcceptGzip<TRequest>(this TRequest request) where TRequest : HttpRequest
|
||||
{
|
||||
// 获取请求头中的接受编码信息
|
||||
@@ -580,7 +580,7 @@ public static partial class HttpExtensions
|
||||
/// 判断请求头中是否包含升级连接
|
||||
/// </summary>
|
||||
/// <param name="request">请求对象,泛型参数,要求是HttpRequest的子类或实现</param>
|
||||
/// <returns>如果请求头中包含升级连接,则返回true;否则返回false</returns>
|
||||
/// <returns>如果请求头中包含升级连接,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
public static bool IsUpgrade<TRequest>(this TRequest request) where TRequest : HttpRequest
|
||||
{
|
||||
// 比较请求头中的连接类型是否为升级类型,忽略大小写
|
||||
|
||||
@@ -57,7 +57,7 @@ public class ReadonlyMemoryHttpContent : HttpContent
|
||||
return true;
|
||||
}
|
||||
|
||||
//返回false,提示后续数据可能太大,通过WriteContent执行。
|
||||
//返回<see langword="false"/>,提示后续数据可能太大,通过WriteContent执行。
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public interface IContentTypeProvider
|
||||
/// </summary>
|
||||
/// <param name="subpath">文件路径</param>
|
||||
/// <param name="contentType">MIME类型</param>
|
||||
/// <returns>如果找到匹配的MIME类型则返回true,否则返回false</returns>
|
||||
/// <returns>如果找到匹配的MIME类型则返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
bool TryGetContentType(string subpath, out string contentType);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -52,7 +52,7 @@ public interface IFormCollection : IEnumerable<KeyValuePair<string, string>>
|
||||
/// 判断集合中是否包含指定的键
|
||||
/// </summary>
|
||||
/// <param name="key">要检查的键</param>
|
||||
/// <returns>如果集合包含指定的键,则返回true;否则返回false</returns>
|
||||
/// <returns>如果集合包含指定的键,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
bool ContainsKey(string key);
|
||||
|
||||
/// <summary>
|
||||
@@ -60,6 +60,6 @@ public interface IFormCollection : IEnumerable<KeyValuePair<string, string>>
|
||||
/// </summary>
|
||||
/// <param name="key">要获取值的键</param>
|
||||
/// <param name="value">与指定键关联的值,如果键不存在则为null</param>
|
||||
/// <returns>如果键存在于集合中,则返回true;否则返回false</returns>
|
||||
/// <returns>如果键存在于集合中,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
bool TryGetValue(string key, out string value);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class StaticFilesPool : DisposableObject
|
||||
/// <param name="key">缓存键</param>
|
||||
/// <param name="value">缓存值,以字节数组形式存储</param>
|
||||
/// <param name="millisecondsTimeout">缓存条目的超时时间,以毫秒为单位</param>
|
||||
/// <returns>始终返回true,表示添加操作已完成</returns>
|
||||
/// <returns>始终返回<see langword="true"/>,表示添加操作已完成</returns>
|
||||
public bool AddEntry(string key, byte[] value, TimeSpan millisecondsTimeout)
|
||||
{
|
||||
// 使用WriteLock确保在添加缓存条目时数据的一致性
|
||||
@@ -118,7 +118,7 @@ public class StaticFilesPool : DisposableObject
|
||||
/// <param name="key">要添加的条目的键。</param>
|
||||
/// <param name="value">要添加的条目的值,包含文件信息。</param>
|
||||
/// <param name="millisecondsTimeout">条目过期的时间段,以毫秒为单位。</param>
|
||||
/// <returns>总是返回true,表示条目已成功添加。</returns>
|
||||
/// <returns>总是返回<see langword="true"/>,表示条目已成功添加。</returns>
|
||||
public bool AddEntry(string key, FileInfo value, TimeSpan millisecondsTimeout)
|
||||
{
|
||||
// 使用WriteLock确保在添加条目时数据的一致性
|
||||
@@ -175,7 +175,7 @@ public class StaticFilesPool : DisposableObject
|
||||
/// </summary>
|
||||
/// <param name="key">要查找的键。</param>
|
||||
/// <param name="cacheEntry">找到的缓存项,通过引用返回。</param>
|
||||
/// <returns>如果找到缓存项则返回true;否则返回false。</returns>
|
||||
/// <returns>如果找到缓存项则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public bool TryFindEntry(string key, out StaticEntry cacheEntry)
|
||||
{
|
||||
// 使用读锁来确保并发访问时的一致性
|
||||
@@ -238,7 +238,7 @@ public class StaticFilesPool : DisposableObject
|
||||
/// 检查指定路径的文件夹是否存在于集合中。
|
||||
/// </summary>
|
||||
/// <param name="path">要检查的文件夹路径。</param>
|
||||
/// <returns>如果文件夹存在于集合中,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果文件夹存在于集合中,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public bool ContainsFolder(string path)
|
||||
{
|
||||
// 使用读取锁确保线程安全
|
||||
|
||||
@@ -134,7 +134,7 @@ public class WSDataFrame : DisposableObject, IRequestInfo, IRequestInfoBuilder,
|
||||
header = (header << 1) + (this.RSV1 ? 1 : 0);
|
||||
header = (header << 1) + (this.RSV2 ? 1 : 0);
|
||||
header = (header << 1) + (this.RSV3 ? 1 : 0);
|
||||
header = (header << 4) + (ushort)this.Opcode;
|
||||
header = (header << 4) + (byte)this.Opcode;
|
||||
|
||||
header = this.Mask ? (header << 1) + 1 : (header << 1) + 0;
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ public sealed class WebSocketMessageCombinator
|
||||
/// </summary>
|
||||
/// <param name="dataFrame">待组合的数据帧。</param>
|
||||
/// <param name="webSocketMessage">组合成功的WebSocket消息。</param>
|
||||
/// <returns>如果成功组合则返回true;否则返回false。</returns>
|
||||
/// <returns>如果成功组合则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public bool TryCombine(WSDataFrame dataFrame, out WebSocketMessage webSocketMessage)
|
||||
{
|
||||
var data = dataFrame.PayloadData;
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
namespace TouchSocket.Http.WebSockets;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket数据类型
|
||||
/// WebSocket数据类型。
|
||||
/// 支持最大值为2^4,不能超过16,即0-15
|
||||
/// </summary>
|
||||
public enum WSDataType : ushort
|
||||
public enum WSDataType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示一个中间数据包
|
||||
|
||||
@@ -105,24 +105,7 @@ public abstract class WebSocketCommandLinePlugin : PluginBase, IWebSocketReceive
|
||||
|
||||
try
|
||||
{
|
||||
object result;
|
||||
switch (method.TaskType)
|
||||
{
|
||||
case TaskReturnType.Task:
|
||||
await method.InvokeAsync(this, os).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
result = default;
|
||||
break;
|
||||
|
||||
case TaskReturnType.TaskObject:
|
||||
result = await method.InvokeObjectAsync(this, os).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
break;
|
||||
|
||||
case TaskReturnType.None:
|
||||
default:
|
||||
result = method.Invoke(this, os);
|
||||
break;
|
||||
}
|
||||
|
||||
var result=await method.InvokeAsync(this, os).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
if (method.HasReturn)
|
||||
{
|
||||
await webSocket.SendAsync(this.Converter.Serialize(null, result)).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
|
||||
@@ -102,7 +102,7 @@ public class ModbusRtuMaster : SerialPortClientBase, IModbusRtuMaster
|
||||
/// </summary>
|
||||
/// <param name="modbusRequest">Modbus请求</param>
|
||||
/// <param name="response">Modbus响应</param>
|
||||
/// <returns>如果请求和响应匹配则返回true,否则返回false</returns>
|
||||
/// <returns>如果请求和响应匹配则返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
protected virtual bool SetRun(IModbusRequest modbusRequest, IModbusResponse response)
|
||||
{
|
||||
if (modbusRequest.SlaveId != response.SlaveId)
|
||||
|
||||
@@ -38,7 +38,7 @@ public readonly ref struct MqttV5PropertiesReader<TByteBlock> where TByteBlock :
|
||||
/// </summary>
|
||||
/// <param name="byteBlock">字节块引用。</param>
|
||||
/// <param name="identifier">读取的属性标识符。</param>
|
||||
/// <returns>如果读取成功,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果读取成功,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public bool TryRead(ref TByteBlock byteBlock, out MqttPropertyId identifier)
|
||||
{
|
||||
if (byteBlock.Position >= this.m_endPosition)
|
||||
|
||||
@@ -349,7 +349,7 @@ public abstract class NamedPipeSessionClientBase : ResolverConfigObject, INamedP
|
||||
/// </summary>
|
||||
/// <param name="id">客户端的唯一标识符</param>
|
||||
/// <param name="sessionClient">输出参数,用于返回找到的客户端实例</param>
|
||||
/// <returns>如果找到对应的客户端,则返回true;否则返回false</returns>
|
||||
/// <returns>如果找到对应的客户端,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
protected bool ProtectedTryGetClient(string id, out NamedPipeSessionClientBase sessionClient)
|
||||
{
|
||||
// 调用内部方法尝试获取客户端
|
||||
|
||||
@@ -526,12 +526,12 @@ public abstract class RpcAttribute : Attribute
|
||||
if (isAsync)
|
||||
{
|
||||
// 如果返回类型为空,则默认为Task;否则,构造Task<T>类型
|
||||
return rpcMethod.ReturnType == null ? "Task" : $"Task<{this.GetProxyParameterName(rpcMethod.Info.ReturnParameter)}>";
|
||||
return rpcMethod.RealReturnType == null ? "Task" : $"Task<{this.GetProxyParameterName(rpcMethod.Info.ReturnParameter)}>";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 当非异步调用时,返回void或方法的返回参数名
|
||||
return rpcMethod.ReturnType == null ? "void" : this.GetProxyParameterName(rpcMethod.Info.ReturnParameter);
|
||||
return rpcMethod.RealReturnType == null ? "void" : this.GetProxyParameterName(rpcMethod.Info.ReturnParameter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -291,9 +291,9 @@ public static class CodeGenerator
|
||||
{
|
||||
if (attributeType == att.GetType())
|
||||
{
|
||||
if (rpcMethod.ReturnType != null)
|
||||
if (rpcMethod.RealReturnType != null)
|
||||
{
|
||||
classCodeGenerator.AddTypeString(rpcMethod.ReturnType);
|
||||
classCodeGenerator.AddTypeString(rpcMethod.RealReturnType);
|
||||
}
|
||||
|
||||
var psTypes = rpcMethod.GetNormalParameters().Select(a => a.Type);
|
||||
|
||||
@@ -75,23 +75,22 @@ public abstract class RpcDispatchProxy<TClient, TAttribute> : DispatchProxy wher
|
||||
|
||||
object result = default;
|
||||
|
||||
switch (rpcMethod.TaskType)
|
||||
switch (rpcMethod.ReturnKind)
|
||||
{
|
||||
case TaskReturnType.Task:
|
||||
case MethodReturnKind.Awaitable:
|
||||
{
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.ReturnType, invokeOption, ps);
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.RealReturnType, invokeOption, ps);
|
||||
break;
|
||||
}
|
||||
case TaskReturnType.TaskObject:
|
||||
case MethodReturnKind.AwaitableObject:
|
||||
{
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.ReturnType, invokeOption, ps).GetFalseAwaitResult();
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.RealReturnType, invokeOption, ps).GetFalseAwaitResult();
|
||||
result = value.GenericMethod.Invoke(default, result);
|
||||
break;
|
||||
}
|
||||
case TaskReturnType.None:
|
||||
default:
|
||||
{
|
||||
result = this.GetClient().Invoke(invokeKey, rpcMethod.ReturnType, invokeOption, ps);
|
||||
result = this.GetClient().Invoke(invokeKey, rpcMethod.RealReturnType, invokeOption, ps);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -117,7 +116,7 @@ public abstract class RpcDispatchProxy<TClient, TAttribute> : DispatchProxy wher
|
||||
InvokeKey = invokeKey,
|
||||
RpcMethod = rpcMethod,
|
||||
InvokeOption = invokeOption,
|
||||
GenericMethod = rpcMethod.TaskType == TaskReturnType.TaskObject ? new Method(this.m_fromResultMethod.MakeGenericMethod(rpcMethod.ReturnType)) : default
|
||||
GenericMethod = rpcMethod.ReturnKind == MethodReturnKind.AwaitableObject ? new Method(this.m_fromResultMethod.MakeGenericMethod(rpcMethod.RealReturnType)) : default
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -91,23 +91,22 @@ public abstract class RpcRealityProxy<T, TClient, TAttribute> : RpcRealityProxyB
|
||||
|
||||
object result;
|
||||
|
||||
switch (rpcMethod.TaskType)
|
||||
switch (rpcMethod.ReturnKind)
|
||||
{
|
||||
case TaskReturnType.Task:
|
||||
case MethodReturnKind.Awaitable:
|
||||
{
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.ReturnType, invokeOption, ps);
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.RealReturnType, invokeOption, ps);
|
||||
break;
|
||||
}
|
||||
case TaskReturnType.TaskObject:
|
||||
case MethodReturnKind.AwaitableObject:
|
||||
{
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.ReturnType, invokeOption, ps).GetFalseAwaitResult();
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.RealReturnType, invokeOption, ps).GetFalseAwaitResult();
|
||||
result = value.GenericMethod.Invoke(default, result);
|
||||
break;
|
||||
}
|
||||
case TaskReturnType.None:
|
||||
default:
|
||||
{
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.ReturnType, invokeOption, ps).GetFalseAwaitResult();
|
||||
result = this.GetClient().InvokeAsync(invokeKey, rpcMethod.RealReturnType, invokeOption, ps).GetFalseAwaitResult();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -132,7 +131,7 @@ public abstract class RpcRealityProxy<T, TClient, TAttribute> : RpcRealityProxyB
|
||||
InvokeKey = invokeKey,
|
||||
RpcMethod = rpcMethod,
|
||||
InvokeOption = invokeOption,
|
||||
GenericMethod = rpcMethod.TaskType == TaskReturnType.TaskObject ? new Method(this.m_fromResultMethod.MakeGenericMethod(rpcMethod.ReturnType)) : default
|
||||
GenericMethod = rpcMethod.ReturnKind == MethodReturnKind.AwaitableObject ? new Method(this.m_fromResultMethod.MakeGenericMethod(rpcMethod.RealReturnType)) : default
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -36,13 +36,13 @@ internal sealed class InternalRpcServerProvider : IRpcServerProvider
|
||||
rpcCallContextAccessor.CallContext = callContext;
|
||||
}
|
||||
var ps = callContext.Parameters;
|
||||
var rpcMethod = callContext.RpcMethod;
|
||||
if (rpcMethod is null)
|
||||
var method = callContext.RpcMethod;
|
||||
if (method is null)
|
||||
{
|
||||
return new InvokeResult(InvokeStatus.UnFound);
|
||||
}
|
||||
|
||||
var filters = callContext.RpcMethod.GetFilters();
|
||||
var filters = method.GetFilters();
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < filters.Count; i++)
|
||||
@@ -55,37 +55,15 @@ internal sealed class InternalRpcServerProvider : IRpcServerProvider
|
||||
{
|
||||
var rpcServer = this.GetRpcServer(callContext);
|
||||
|
||||
//调用
|
||||
switch (callContext.RpcMethod.TaskType)
|
||||
if (method.IsAwaitable)
|
||||
{
|
||||
case TaskReturnType.Task:
|
||||
{
|
||||
await ((Task)callContext.RpcMethod.Invoke(rpcServer, ps)).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case TaskReturnType.TaskObject:
|
||||
{
|
||||
invokeResult.Result = await callContext.RpcMethod.InvokeObjectAsync(rpcServer, ps)
|
||||
invokeResult.Result = await callContext.RpcMethod.InvokeAsync(rpcServer, ps)
|
||||
.ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case TaskReturnType.None:
|
||||
{
|
||||
if (callContext.RpcMethod.HasReturn)
|
||||
{
|
||||
invokeResult.Result = callContext.RpcMethod.Invoke(rpcServer, ps);
|
||||
}
|
||||
else
|
||||
{
|
||||
callContext.RpcMethod.Invoke(rpcServer, ps);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
invokeResult.Result = callContext.RpcMethod.Invoke(rpcServer, ps);
|
||||
}
|
||||
invokeResult.Status = InvokeStatus.Success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,8 +392,8 @@ public sealed class SwaggerPlugin : PluginBase, IServerStartedPlugin, IHttpPlugi
|
||||
openApiResponse.Content.Add("text/plain", openApiContent);
|
||||
openApiResponse.Content.Add("text/json", openApiContent);
|
||||
openApiResponse.Content.Add("application/xml", openApiContent);
|
||||
openApiContent.Schema = this.CreateSchema(rpcMethod.ReturnType);
|
||||
this.AddSchemaType(rpcMethod.ReturnType, schemaTypeList);
|
||||
openApiContent.Schema = this.CreateSchema(rpcMethod.RealReturnType);
|
||||
this.AddSchemaType(rpcMethod.RealReturnType, schemaTypeList);
|
||||
}
|
||||
|
||||
openApiPathValue.Responses = new Dictionary<string, OpenApiResponse>();
|
||||
|
||||
@@ -169,7 +169,7 @@ public sealed class WebApiAttribute : RpcAttribute
|
||||
var parameterInfos = webApiParameterInfos.Where(a => a.IsFromHeader);
|
||||
var list = parameterInfos.Select(a => $"new KeyValuePair<string, string>(\"{a.FromHeaderName}\",{GetParameterToString(a.Parameter)})").ToList();
|
||||
|
||||
if (rpcMethod.HasReturn && rpcMethod.ReturnType == typeof(string))
|
||||
if (rpcMethod.HasReturn && rpcMethod.RealReturnType == typeof(string))
|
||||
{
|
||||
list.Add($"new KeyValuePair<string, string>(\"Accept\",\"text/plain\")");
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public abstract class SslOption
|
||||
/// <param name="certificate">客户端证书</param>
|
||||
/// <param name="chain">证书链</param>
|
||||
/// <param name="sslPolicyErrors">SSL策略错误</param>
|
||||
/// <returns>总是返回true,表示接受证书</returns>
|
||||
/// <returns>总是返回<see langword="true"/>,表示接受证书</returns>
|
||||
private bool OnCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -41,7 +41,7 @@ public interface INatSessionClient : ITcpSession, ITcpListenableClient, IClient,
|
||||
/// 移除目标客户端。
|
||||
/// </summary>
|
||||
/// <param name="client">要移除的TCP客户端。</param>
|
||||
/// <returns>如果移除成功则返回true,否则返回false。</returns>
|
||||
/// <returns>如果移除成功则返回<see langword="true"/>,否则返回<see langword="false"/>。</returns>
|
||||
bool RemoveTargetClient(NatTargetClient client);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -526,10 +526,9 @@ public abstract class TcpSessionClientBase : ResolverConfigObject, ITcpSession,
|
||||
/// <param name="sourceId">原始Id</param>
|
||||
/// <param name="targetId">目标Id</param>
|
||||
/// <returns>异步任务</returns>
|
||||
protected virtual Task IdChanged(string sourceId, string targetId)
|
||||
protected virtual async Task IdChanged(string sourceId, string targetId)
|
||||
{
|
||||
//此处无需执行任何操作,直接返回一个已完成的异步任务
|
||||
return EasyTask.CompletedTask;
|
||||
await this.PluginManager.RaiseAsync(typeof(IIdChangedPlugin), this.Resolver, this, new IdChangedEventArgs(sourceId,targetId)).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -620,7 +619,7 @@ public abstract class TcpSessionClientBase : ResolverConfigObject, ITcpSession,
|
||||
/// </summary>
|
||||
/// <param name="id">客户端的唯一标识符</param>
|
||||
/// <param name="sessionClient">输出参数,用于返回找到的客户端实例</param>
|
||||
/// <returns>如果找到对应的客户端,则返回true;否则返回false</returns>
|
||||
/// <returns>如果找到对应的客户端,则返回<see langword="true"/>;否则返回<see langword="false"/></returns>
|
||||
protected bool ProtectedTryGetClient(string id, out TcpSessionClientBase sessionClient)
|
||||
{
|
||||
// 调用内部方法m_tryGet来尝试获取客户端
|
||||
|
||||
@@ -50,7 +50,7 @@ public struct UdpFrame
|
||||
/// 解析给定的只读字节跨度数据。
|
||||
/// </summary>
|
||||
/// <param name="span">待解析的只读字节跨度。</param>
|
||||
/// <returns>如果解析成功,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果解析成功,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public unsafe bool Parse(ReadOnlySpan<byte> span)
|
||||
{
|
||||
// 获取输入跨度的长度
|
||||
@@ -87,10 +87,10 @@ public struct UdpFrame
|
||||
}
|
||||
}
|
||||
|
||||
// 成功解析输入跨度数据,返回true
|
||||
// 成功解析输入跨度数据,返回<see langword="true"/>
|
||||
return true;
|
||||
}
|
||||
// 输入长度不足,无法解析,返回false
|
||||
// 输入长度不足,无法解析,返回<see langword="false"/>
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public static class ServiceExtension
|
||||
/// <param name="connectableService">一个实现了<see cref="IConnectableService{TClient}"/>接口的可连接服务对象。</param>
|
||||
/// <param name="id">要获取的客户端的唯一标识符。</param>
|
||||
/// <param name="client">如果找到匹配的客户端,则设置此参数为该客户端对象;如果未找到,则设置为default(TClient)。</param>
|
||||
/// <returns>如果找到匹配的客户端,则返回true;否则返回false。</returns>
|
||||
/// <returns>如果找到匹配的客户端,则返回<see langword="true"/>;否则返回<see langword="false"/>。</returns>
|
||||
public static bool TryGetClient<TClient>(this IConnectableService<TClient> connectableService, string id, out TClient client)
|
||||
where TClient : IIdClient, IClient
|
||||
{
|
||||
|
||||
@@ -95,7 +95,7 @@ public static class SocketPluginManagerExtension
|
||||
/// </summary>
|
||||
/// <param name="pluginManager"></param>
|
||||
/// <param name="sleepTime">失败时间隔时间</param>
|
||||
/// <param name="failCallback">失败时回调(参数依次为:客户端,本轮尝试重连次数,异常信息)。如果回调为null或者返回false,则终止尝试下次连接。</param>
|
||||
/// <param name="failCallback">失败时回调(参数依次为:客户端,本轮尝试重连次数,异常信息)。如果回调为null或者返回<see langword="false"/>,则终止尝试下次连接。</param>
|
||||
/// <param name="successCallback">成功连接时回调。</param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,请使用UseTcpReconnection代替", true)]
|
||||
|
||||
@@ -42,7 +42,7 @@ public interface IClientCollection<TClient> : IEnumerable<TClient> where TClient
|
||||
/// 判断指定Id的客户端是否存在于集合中
|
||||
/// </summary>
|
||||
/// <param name="id">要查找的客户端的唯一标识符</param>
|
||||
/// <returns>如果集合中存在该Id对应的客户端返回true,否则返回false</returns>
|
||||
/// <returns>如果集合中存在该Id对应的客户端返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
bool ClientExist(string id);
|
||||
|
||||
/// <summary>
|
||||
@@ -50,6 +50,6 @@ public interface IClientCollection<TClient> : IEnumerable<TClient> where TClient
|
||||
/// </summary>
|
||||
/// <param name="id">要获取的客户端的唯一标识符</param>
|
||||
/// <param name="client">输出参数,用于存储找到的客户端对象</param>
|
||||
/// <returns>如果找到对应的客户端对象返回true,否则返回false</returns>
|
||||
/// <returns>如果找到对应的客户端对象返回<see langword="true"/>,否则返回<see langword="false"/></returns>
|
||||
bool TryGetClient(string id, out TClient client);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public abstract class ReconnectionPlugin<TClient> : PluginBase, ILoadedConfigPlu
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每个周期可执行的委托。用于检验客户端活性。返回true表示存活,返回
|
||||
/// 每个周期可执行的委托。用于检验客户端活性。返回<see langword="true"/>表示存活,返回
|
||||
/// </summary>
|
||||
public abstract Func<TClient, int, Task<bool?>> ActionForCheck { get; set; }
|
||||
|
||||
@@ -113,7 +113,7 @@ public abstract class ReconnectionPlugin<TClient> : PluginBase, ILoadedConfigPlu
|
||||
/// 设置连接动作
|
||||
/// </summary>
|
||||
/// <param name="sleepTime">失败时间隔时间</param>
|
||||
/// <param name="failCallback">失败时回调(参数依次为:客户端,本轮尝试重连次数,异常信息)。如果回调为null或者返回false,则终止尝试下次连接。</param>
|
||||
/// <param name="failCallback">失败时回调(参数依次为:客户端,本轮尝试重连次数,异常信息)。如果回调为null或者返回<see langword="false"/>,则终止尝试下次连接。</param>
|
||||
/// <param name="successCallback">成功连接时回调</param>
|
||||
/// <returns></returns>
|
||||
public ReconnectionPlugin<TClient> SetConnectAction(TimeSpan sleepTime,
|
||||
|
||||
@@ -106,23 +106,7 @@ public abstract class TcpCommandLinePlugin : PluginBase, ITcpReceivedPlugin
|
||||
|
||||
try
|
||||
{
|
||||
object result;
|
||||
switch (method.TaskType)
|
||||
{
|
||||
case TaskReturnType.Task:
|
||||
await method.InvokeAsync(this, os).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
result = default;
|
||||
break;
|
||||
|
||||
case TaskReturnType.TaskObject:
|
||||
result = await method.InvokeObjectAsync(this, os).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
break;
|
||||
|
||||
case TaskReturnType.None:
|
||||
default:
|
||||
result = method.Invoke(this, os);
|
||||
break;
|
||||
}
|
||||
var result=await method.InvokeAsync(this, os).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
if (method.HasReturn)
|
||||
{
|
||||
await clientSender.SendAsync(this.Converter.Serialize(null, result)).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
|
||||
Reference in New Issue
Block a user