V18 / 8d896b8a86e5
ReflectionApi.cs
Interfaces/Gui/LilithGui.Worker/ReflectionApi.cs
Unchanged from the preceding versionCS
using System.Reflection;
using System.Text.Json;
namespace Lilith.Gui.Worker;
internal static class ReflectionApi
{
internal static object? Get(object? value,string property)=>value?.GetType().GetProperty(property,BindingFlags.Public|BindingFlags.Instance)?.GetValue(value);
internal static object Create(Type type,IReadOnlyDictionary<string,object?> values)
{
var constructor=type.GetConstructors().OrderByDescending(c=>c.GetParameters().Length).First();
return constructor.Invoke(Arguments(constructor.GetParameters(),values));
}
private static object?[] Arguments(ParameterInfo[] parameters,IReadOnlyDictionary<string,object?> values)=>parameters.Select(p=>
{
var match=values.FirstOrDefault(v=>string.Equals(v.Key,p.Name,StringComparison.OrdinalIgnoreCase));
if(match.Key is not null)return ConvertValue(match.Value,p.ParameterType);
return p.HasDefaultValue?p.DefaultValue:p.ParameterType==typeof(CancellationToken)?CancellationToken.None:throw new ArgumentException("Missing "+p.Name);
}).ToArray();
private static object? ConvertValue(object? value,Type type)
{
if(value is null||type.IsInstanceOfType(value))return value;
if(type.IsEnum)return Enum.Parse(type,value.ToString()!,true);
if(value is JsonElement json)return JsonSerializer.Deserialize(json.GetRawText(),type,new JsonSerializerOptions{PropertyNameCaseInsensitive=true});
return Convert.ChangeType(value,Nullable.GetUnderlyingType(type)??type,System.Globalization.CultureInfo.InvariantCulture);
}
internal static async Task<object?> Call(object target,string method,IReadOnlyDictionary<string,object?>? values=null)
{
var candidates=target.GetType().GetMethods(BindingFlags.Public|BindingFlags.Instance).Where(m=>m.Name==method).OrderByDescending(m=>m.GetParameters().Length).ToArray();
if(candidates.Length==0)throw new NotSupportedException("This release does not expose "+method+".");
object? result=candidates[0].Invoke(target,Arguments(candidates[0].GetParameters(),values??new Dictionary<string,object?>()));
if(result is Task task){await task;return task.GetType().GetProperty("Result")?.GetValue(task);}
return result;
}
internal static void Attach(object target,string name,Action<object> callback)
{
var info=target.GetType().GetEvent(name);if(info?.EventHandlerType is null)return;
info.AddEventHandler(target,new EventForwarder(callback).Create(info.EventHandlerType));
}
internal sealed class EventForwarder(Action<object> callback)
{
public void Forward<T>(T value)=>callback(value!);
internal Delegate Create(Type delegateType)=>GetType().GetMethod(nameof(Forward))!.MakeGenericMethod(delegateType.GenericTypeArguments[0]).CreateDelegate(delegateType,this);
}
}