Unity Udexreal开发插件包
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
13 KiB

//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
namespace TouchSocket.Core
{
/// <summary>
/// Task类型
/// </summary>
public enum TaskReturnType
{
/// <summary>
/// 没有Task
/// </summary>
None,
/// <summary>
/// 仅返回Task
/// </summary>
Task,
/// <summary>
/// 返回Task的值
/// </summary>
TaskObject
}
/// <summary>
/// 表示方法
/// </summary>
public class Method
{
private readonly MethodInfo m_info;
/// <summary>
/// 方法执行委托
/// </summary>
private readonly Func<object, object[], object> m_invoker;
private readonly bool m_isByRef;
/// <summary>
/// 方法
/// </summary>
/// <param name="method">方法信息</param>
public Method(MethodInfo method)
{
m_info = method ?? throw new ArgumentNullException(nameof(method));
Name = method.Name;
Static = method.IsStatic;
foreach (var item in method.GetParameters())
{
if (item.ParameterType.IsByRef)
{
m_isByRef = true;
}
}
if (this.m_isByRef||GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
if (method.ReturnType == typeof(Task))
{
HasReturn = false;
TaskType = TaskReturnType.Task;
}
else if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
{
HasReturn = true;
ReturnType = method.ReturnType.GetGenericArguments()[0];
TaskType = TaskReturnType.TaskObject;
}
else if (method.ReturnType == typeof(void))
{
HasReturn = false;
TaskType = TaskReturnType.None;
}
else
{
HasReturn = true;
TaskType = TaskReturnType.None;
ReturnType = method.ReturnType;
}
}
else
{
m_invoker = CreateInvoker(method);
}
}
/// <summary>
/// 是否具有返回值
/// </summary>
public bool HasReturn { get; private set; }
/// <summary>
/// 方法信息
/// </summary>
public MethodInfo Info => m_info;
/// <summary>
/// 是否有引用类型
/// </summary>
public bool IsByRef => m_isByRef;
/// <summary>
/// 获取方法名
/// </summary>
public string Name { get; protected set; }
/// <summary>
/// 返回值类型。
/// <para>当方法为void或task时,为null</para>
/// <para>当方法为task泛型时,为泛型元素类型</para>
/// </summary>
public Type ReturnType { get; private set; }
/// <summary>
/// 是否为静态函数
/// </summary>
public bool Static { get; private set; }
/// <summary>
/// 返回值的Task类型。
/// </summary>
public TaskReturnType TaskType { get; private set; }
/// <summary>
/// 执行方法。
/// <para>当方法为void或task时,会返回null</para>
/// <para>当方法为task泛型时,会wait后的值</para>
/// <para>注意:当调用方为UI主线程时,调用异步方法,则极有可能发生死锁。</para>
/// </summary>
/// <param name="instance">实例</param>
/// <param name="parameters">参数</param>
/// <returns></returns>
public object Invoke(object instance, params object[] parameters)
{
switch (TaskType)
{
case TaskReturnType.None:
{
object re;
if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
re = m_info.Invoke(instance, parameters);
}
else
{
re = m_invoker.Invoke(instance, parameters);
}
return re;
}
case TaskReturnType.Task:
{
object re;
if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
re = m_info.Invoke(instance, parameters);
}
else
{
re = m_invoker.Invoke(instance, parameters);
}
Task task = (Task)re;
task.Wait();
return default;
}
case TaskReturnType.TaskObject:
{
object re;
if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
re = m_info.Invoke(instance, parameters);
}
else
{
re = m_invoker.Invoke(instance, parameters);
}
Task task = (Task)re;
task.Wait();
return task.GetType().GetProperty("Result").GetValue(task);
}
default:
return default;
}
}
/// <summary>
/// 异步调用
/// </summary>
/// <param name="instance"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public Task InvokeAsync(object instance, params object[] parameters)
{
switch (TaskType)
{
case TaskReturnType.None:
{
throw new Exception("该方法不包含Task。");
}
case TaskReturnType.Task:
{
object re;
if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
re = m_info.Invoke(instance, parameters);
}
else
{
re = m_invoker.Invoke(instance, parameters);
}
return (Task)re;
}
case TaskReturnType.TaskObject:
{
object re;
if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
re = m_info.Invoke(instance, parameters);
}
else
{
re = m_invoker.Invoke(instance, parameters);
}
return (Task)re;
}
default:
return default;
}
}
/// <summary>
/// 调用异步结果
/// </summary>
/// <param name="instance"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public async Task<object> InvokeObjectAsync(object instance, params object[] parameters)
{
switch (TaskType)
{
case TaskReturnType.None:
{
object re;
if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
re = m_info.Invoke(instance, parameters);
}
else
{
re = m_invoker.Invoke(instance, parameters);
}
return re;
}
case TaskReturnType.Task:
{
object re;
if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
re = m_info.Invoke(instance, parameters);
}
else
{
re = m_invoker.Invoke(instance, parameters);
}
Task task = (Task)re;
await task;
return default;
}
case TaskReturnType.TaskObject:
{
object re;
if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity))
{
re = m_info.Invoke(instance, parameters);
}
else
{
re = m_invoker.Invoke(instance, parameters);
}
Task task = (Task)re;
await task;
return task.GetType().GetProperty("Result").GetValue(task);
}
default:
return default;
}
}
/// <summary>
/// 生成方法的调用委托
/// </summary>
/// <param name="method">方法成员信息</param>
/// <exception cref="ArgumentException"></exception>
/// <returns></returns>
private Func<object, object[], object> CreateInvoker(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))
{
HasReturn = false;
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<>))
{
TaskType = TaskReturnType.TaskObject;
HasReturn = true;
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))
{
HasReturn = false;
TaskType = TaskReturnType.None;
var action = Expression.Lambda<Action<object, object[]>>(body, instance, parameters).Compile();
return (_instance, _parameters) =>
{
action.Invoke(_instance, _parameters);
return null;
};
}
else
{
HasReturn = true;
TaskType = TaskReturnType.None;
ReturnType = method.ReturnType;
var bodyCast = Expression.Convert(body, typeof(object));
return Expression.Lambda<Func<object, object[], object>>(bodyCast, instance, parameters).Compile();
}
}
}
}