Avalonia配置,参考https://www.cnblogs.com/dalgleish/p/18967204

随时更新,目前已支持多个cs文件动态编译。

AvaloniaExtensions.cs代码

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.Threading;
using Avalonia.VisualTree;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Shares.Avalonia
{
    public static class AvaloniaExtensions
    {
        public static IResourceDictionary WindowResources(this Control topLevel)
        {
            return Application.Current?.Resources!;
        }
        public static IClassicDesktopStyleApplicationLifetime? GetDesktopLifetime()
        {
            return Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime;
        }
        public static Control Create(this Control topLevel, string target, params object[] parameters)
        {
            var viewType = Type.GetType($"{target}, {target.Split(".")[0]}");
            if (viewType == null)
                return CreateErrorControl($"报错:无法找到类型 \"{target}\",请确保其已位于正确命名空间");
            return (Control)Activator.CreateInstance(viewType, args: parameters)!;
        }
        // 缓存已编译代码的 Assembly
        private static readonly ConcurrentDictionary<string, Assembly> assemblyCache = new();

        //单文件编译
        public static async Task<Control> RunXamlAsync(this Control topLevel, string? xaml, string? code, string cls = "SampleView")
        {
            if (string.IsNullOrWhiteSpace(xaml))
                return CreateErrorControl("XAML代码为空,请提供有效的 XAML。");

            string key = $"{xaml.GetHashCode()}_{code?.GetHashCode() ?? 0}_{cls}";

            try
            {
                Assembly? scriptAssembly = null;
                object? rootInstance = null;

                if (!string.IsNullOrWhiteSpace(code))
                {
                    if (!assemblyCache.TryGetValue(key, out scriptAssembly))
                    {
                        var (assembly, _) = await CompilerService.GetScriptAssembly(code);
                        if (assembly == null)
                            return CreateErrorControl("C# 代码编译失败,请检查语法。");

                        assemblyCache[key] = assembly;
                        scriptAssembly = assembly;
                    }

                    var sampleViewType = scriptAssembly.GetTypes()
                        .FirstOrDefault(t => t.Name == cls);

                    if (sampleViewType == null)
                        return CreateErrorControl($"在编译结果中未找到类型 \"{cls}\",请确保定义了该类。");

                    rootInstance = Activator.CreateInstance(sampleViewType);
                }

                Control? control;

                if (scriptAssembly != null && rootInstance != null)
                {
                    await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml));
                    control = AvaloniaRuntimeXamlLoader.Load(stream, scriptAssembly, rootInstance) as Control;
                }
                else
                {
                    control = AvaloniaRuntimeXamlLoader.Parse<Control?>(xaml);
                }

                if (control is Window w)
                {
                    if (w.Content is string str)
                        control = new Label() { Content = str };
                    else
                        control = (Control)w.Content!;
                }

                return control ?? CreateErrorControl("XAML加载失败,返回了空控件。");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return CreateErrorControl("发生异常:" + ex.Message);
            }
        }
        //多文件编译
        /*
         * var codeFiles = new Dictionary<string, string>
          {
             ["SampleView.cs"] = File.ReadAllText("SampleView.cs"),
             ["SampleViewModel.cs"] = File.ReadAllText("SampleViewModel.cs")
        };
         */
        public static async Task<Control> RunXamlAsync(this Control topLevel, string? xaml, Dictionary<string, string>? codeFiles, string cls = "SampleView")
        {
            if (string.IsNullOrWhiteSpace(xaml))
                return CreateErrorControl("XAML代码为空,请提供有效的 XAML。");

            string key = $"{xaml.GetHashCode()}_{(codeFiles is null ? 0 : string.Join(",", codeFiles.Keys).GetHashCode())}_{cls}";

            try
            {
                Assembly? scriptAssembly = null;
                object? rootInstance = null;

                if (codeFiles is not null && codeFiles.Count > 0)
                {
                    if (!assemblyCache.TryGetValue(key, out scriptAssembly))
                    {
                        var (assembly, _) = await CompilerService.GetScriptAssembly(codeFiles);
                        if (assembly == null)
                            return CreateErrorControl("C# 多文件代码编译失败,请检查语法。");

                        assemblyCache[key] = assembly;
                        scriptAssembly = assembly;
                    }

                    var sampleViewType = scriptAssembly.GetTypes()
                        .FirstOrDefault(t => t.Name == cls);

                    if (sampleViewType == null)
                        return CreateErrorControl($"在编译结果中未找到类型 \"{cls}\",请确保在源码中正确定义。");

                    rootInstance = Activator.CreateInstance(sampleViewType);
                }

                Control? control;

                if (scriptAssembly != null && rootInstance != null)
                {
                    await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml));
                    control = AvaloniaRuntimeXamlLoader.Load(stream, scriptAssembly, rootInstance) as Control;
                }
                else
                {
                    control = AvaloniaRuntimeXamlLoader.Parse<Control?>(xaml);
                }

                if (control is Window w)
                {
                    if (w.Content is string str)
                        control = new Label() { Content = str };
                    else
                        control = (Control)w.Content!;
                }

                return control ?? CreateErrorControl("XAML加载失败,返回了空控件。");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return CreateErrorControl("发生异常:" + ex.Message);
            }
        }

        //不可用
        public static async Task<Control> RunAvaresResourceAsync(this Control topLevel, string fileName, string? code = null, string cls = "SampleView")
        {
            var assembly = topLevel.GetType().Assembly;
            var assemblyName = assembly.GetName().Name;
            var baseUri = new Uri($"avares://{assemblyName}");

            try
            {
                // 获取所有资源并匹配文件名
                var allResources = AssetLoader.GetAssets(baseUri, null);
                var resourceUri = allResources.FirstOrDefault(u =>
                    u.AbsolutePath.EndsWith(fileName, StringComparison.OrdinalIgnoreCase));

                if (resourceUri == null)
                {
                    var available = string.Join("\n", allResources.Select(u => u.AbsolutePath));
                    return CreateErrorControl($"找不到 {fileName}\n可用资源:\n{available}");
                }
                Stream resourceStream = AssetLoader.Open(resourceUri);
                using var reader = new StreamReader(resourceStream);
                var xaml = await reader.ReadToEndAsync();
                return await topLevel.RunXamlAsync(xaml, code, cls);
            }
            catch (Exception ex)
            {
                return CreateErrorControl($"加载错误: {ex.Message}");
            }
        }
        public static async Task<Control> RunResourceAsync(this Control topLevel, string fileName)
        {
            var assembly = topLevel.GetType().Assembly;

            try
            {
                var path = $"{assembly.GetName().Name}.{fileName}";

                // UI代码必须在主线程中执行
                return await Dispatcher.UIThread.InvokeAsync(() =>
                {
                    Control? control = topLevel.Create(path);

                    if (control is Window w)
                    {
                        if (w.Content is string str)
                            control = new Label() { Content = str };
                        else
                            control = (Control)w.Content!;
                    }

                    return control ?? CreateErrorControl("XAML加载失败,返回了空控件。");
                });
            }
            catch (Exception ex)
            {
                return await Dispatcher.UIThread.InvokeAsync(() =>
                    CreateErrorControl("发生异常:" + ex.Message));
            }
        }

        private static Control CreateErrorControl(string message)
        {
            return new Border
            {
                Background = Brushes.MistyRose,
                BorderBrush = Brushes.IndianRed,
                BorderThickness = new Thickness(1),
                Padding = new Thickness(1),
                Child = new TextBlock
                {
                    Text = message,
                    Foreground = Brushes.DarkRed,
                    FontWeight = FontWeight.Bold,
                    TextWrapping = TextWrapping.Wrap,
                    HorizontalAlignment = HorizontalAlignment.Center,
                    VerticalAlignment = VerticalAlignment.Center,
                },
            };
        }
        //RoutedEventArgs扩展
        public static object? OriginalSource(this RoutedEventArgs e)
        {
            return GetDesktopLifetime()?.MainWindow;
        }
        //命令行
        public static string[]? GetCommandLine(this Control topLevel)
        {
            return GetDesktopLifetime()?.Args;
        }
        //读取文件
        public static async Task<string?> ReadAllTextAsync(this Control topLevel, string fileName)
        {
            var assembly = topLevel.GetType().Assembly;
            var assemblyName = assembly.GetName().Name;
            var baseUri = new Uri($"avares://{assemblyName}");
            var allResources = AssetLoader.GetAssets(baseUri, null);
            var resourceUri = allResources.FirstOrDefault(u =>
                u.AbsolutePath.EndsWith(fileName, StringComparison.OrdinalIgnoreCase));

            if (resourceUri == null)
                return null;
            Stream resourceStream = AssetLoader.Open(resourceUri);
            using var reader = new StreamReader(resourceStream);
            var content = await reader.ReadToEndAsync();
            return content;
        }
        public static void SetZIndex(this Control topLevel, int index)
            => topLevel.SetValue(Panel.ZIndexProperty, index);
        public static int GetZIndex(this Control topLevel)
            => topLevel.GetValue(Panel.ZIndexProperty);
        public static T? GetService<T>()
        {
            var serviceType = typeof(T);
            Console.WriteLine($"尝试获取服务类型:{serviceType.FullName}");

            var locatorType = typeof(AvaloniaLocator);
            PropertyInfo? currentProp = null;
            Type? typeWalker = locatorType;

            while (typeWalker != null)
            {
                currentProp = typeWalker.GetProperty("Current", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                if (currentProp != null)
                {
                    Console.WriteLine("找到 AvaloniaLocator.Current 属性");
                    break;
                }
                typeWalker = typeWalker.BaseType;
            }

            if (currentProp == null)
            {
                Console.WriteLine("未找到 AvaloniaLocator.Current 属性");
                return default;
            }

            var currentLocator = currentProp.GetValue(null);
            if (currentLocator == null)
            {
                Console.WriteLine("AvaloniaLocator.Current 返回 null");
                return default;
            }

            // 尝试调用泛型方法 GetService<T>()
            var methods = currentLocator.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                .Where(m => m.Name == "GetService" && m.IsGenericMethod);
            MethodInfo? genericMethod = methods.FirstOrDefault();
            if (genericMethod != null)
            {
                try
                {
                    var result = genericMethod.MakeGenericMethod(serviceType).Invoke(currentLocator, null);
                    if (result is T t)
                    {
                        Console.WriteLine($"通过泛型方法获取服务成功:{serviceType.FullName}");
                        return t;
                    }
                    else
                    {
                        Console.WriteLine($"泛型方法返回结果为空或类型不匹配");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"调用泛型方法 GetService<T>() 异常:{ex.Message}");
                }
            }

            // 回退:GetService(Type)
            MethodInfo? getServiceByType = currentLocator.GetType().GetMethod("GetService", new[] { typeof(Type) });
            if (getServiceByType != null)
            {
                try
                {
                    var service = getServiceByType.Invoke(currentLocator, new object[] { serviceType });
                    if (service is T t2)
                    {
                        Console.WriteLine($"通过 GetService(Type) 获取服务成功:{serviceType.FullName}");
                        return t2;
                    }
                    else
                    {
                        Console.WriteLine($"GetService(Type) 返回结果为空或类型不匹配");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"调用 GetService(Type) 异常:{ex.Message}");
                }
            }

            // 回退实例或创建
            try
            {
                var instanceProp = serviceType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                if (instanceProp != null)
                {
                    var instance = instanceProp.GetValue(null);
                    if (instance is T typedInstance)
                    {
                        Console.WriteLine($"通过静态 Instance 属性获取服务成功:{serviceType.FullName}");
                        return typedInstance;
                    }
                    else
                    {
                        Console.WriteLine($"Instance 属性为空或类型不匹配");
                    }
                }

                if (!serviceType.IsAbstract)
                {
                    var created = Activator.CreateInstance(serviceType);
                    if (created is T createdTyped)
                    {
                        Console.WriteLine($"通过 Activator.CreateInstance 创建服务成功:{serviceType.FullName}");
                        return createdTyped;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"尝试通过 Instance 或 Activator 创建服务失败:{ex.Message}");
            }

            Console.WriteLine($"未能获取服务:{serviceType.FullName}");
            return default;
        }
 
        //外接矩形
        public static Rect GetMinBoundingMatrix(Visual visual, Visual relativeTo)
        {
            if (visual == null || relativeTo == null)
                return new Rect();

            var transform = visual.TransformToVisual(relativeTo);

            if (transform is null)
                return new Rect();

            var bounds = visual.Bounds;

            // 四个角点(本地坐标)
            var points = new[]
            {
                new Point(0, 0),
                new Point(bounds.Width, 0),
                new Point(bounds.Width, bounds.Height),
                new Point(0, bounds.Height)
            };

            // 应用变换
            var transformed = points.Select(p => transform.Value.Transform(p)).ToArray();

            // 计算外接矩形
            var minX = transformed.Min(p => p.X);
            var maxX = transformed.Max(p => p.X);
            var minY = transformed.Min(p => p.Y);
            var maxY = transformed.Max(p => p.Y);

            return new Rect(minX, minY, maxX - minX, maxY - minY);
        }
        //递归应用矩阵变化
        public static TransformedBounds? GetTransformedBounds(Visual visual, Visual relativeTo)
        {
            if (visual == null || relativeTo == null)
                return null;

            Rect clip = new Rect();
            var transform = Matrix.Identity;

            bool Visit(Visual v)
            {
                if (!v.IsVisible)
                    return false;

                var bounds = new Rect(v.Bounds.Size);

                if (v == relativeTo)
                {
                    clip = bounds;
                    transform = Matrix.Identity;
                    return true;
                }

                var parent = v.GetVisualParent();
                if (parent == null)
                    return false;

                if (!Visit(parent))
                    return false;

                // 计算当前节点的渲染变换矩阵
                var renderTransform = Matrix.Identity;

                if (v.HasMirrorTransform)
                {
                    var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, v.Bounds.Width, 0);
                    renderTransform *= mirrorMatrix;
                }

                if (v.RenderTransform != null)
                {
                    var origin = v.RenderTransformOrigin.ToPixels(bounds.Size);
                    var offset = Matrix.CreateTranslation(origin);
                    var finalTransform = (-offset) * v.RenderTransform.Value * offset;
                    renderTransform *= finalTransform;
                }

                // 叠加变换矩阵
                transform = renderTransform *
                            Matrix.CreateTranslation(v.Bounds.Position) *
                            transform;

                // 处理剪裁
                if (v.ClipToBounds)
                {
                    var globalBounds = bounds.TransformToAABB(transform);
                    var clipBounds = v.ClipToBounds ? globalBounds.Intersect(clip) : clip;
                    clip = clip.Intersect(clipBounds);
                }

                return true;
            }

            return Visit(visual) ? new TransformedBounds(new Rect(visual.Bounds.Size), clip, transform) : null;
        }
        //获取所有command
        public static List<ICommand> GetICommands(this Control topLevel)
        {
            var commands = new HashSet<ICommand>();

            // 1. 先查 DataContext 中的所有 ICommand 属性
            if (topLevel.DataContext != null)
            {
                var props = topLevel.DataContext.GetType()
                    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .Where(p => typeof(ICommand).IsAssignableFrom(p.PropertyType));
                foreach (var prop in props)
                {
                    if (prop.GetValue(topLevel.DataContext) is ICommand cmd)
                        commands.Add(cmd);
                }
            }

            // 2. 再查控件自身的 ICommandSource.Command
            if (topLevel is ICommandSource commandSource && commandSource.Command != null)
            {
                commands.Add(commandSource.Command);
            }

            // 3. 子控件递归
            foreach (var child in topLevel.GetVisualChildren())
            {
                if (child is Control c)
                    commands.UnionWith(GetICommands(c));
            }

            return commands.ToList();
        }

        //在控件树及其 DataContext 中按名称查找所有 ICommand(允许省略 "Command" 后缀,去重)
        public static List<ICommand> GetICommands(this Control topLevel, string name)
        {
            var commands = new HashSet<ICommand>();
            string fullName = name.EndsWith("Command") ? name : name + "Command";

            // 当前控件:DataContext
            if (topLevel.DataContext != null)
            {
                var prop = topLevel.DataContext.GetType().GetProperty(fullName, BindingFlags.Public | BindingFlags.Instance);
                if (prop != null && typeof(ICommand).IsAssignableFrom(prop.PropertyType))
                {
                    if (prop.GetValue(topLevel.DataContext) is ICommand cmd)
                        commands.Add(cmd);
                }
            }

            // 当前控件:ICommandSource
            if (topLevel is ICommandSource commandSource && commandSource.Command != null)
            {
                if (topLevel.Name == name || topLevel.Name == fullName ||
                    commandSource.Command.GetType().Name == name || commandSource.Command.GetType().Name == fullName)
                    commands.Add(commandSource.Command);
            }

            // 递归子控件
            foreach (var child in topLevel.GetVisualChildren())
            {
                if (child is Control c)
                    commands.UnionWith(GetICommands(c, name)); // 递归并去重
            }

            return commands.ToList();
        }
        public static ICommand? GetICommand(this Control topLevel, string name)
        {
            // 自动补 "Command" 后缀
            string fullName = name.EndsWith("Command") ? name : name + "Command";

            // 1. 当前控件:检查 DataContext 是否有这个命令
            if (topLevel.DataContext != null)
            {
                var prop = topLevel.DataContext.GetType().GetProperty(fullName, BindingFlags.Public | BindingFlags.Instance);
                if (prop != null && typeof(ICommand).IsAssignableFrom(prop.PropertyType))
                {
                    return (ICommand?)prop.GetValue(topLevel.DataContext);
                }
            }

            // 2. 当前控件:如果是 ICommandSource 并且匹配名称
            if (topLevel is ICommandSource commandSource && commandSource.Command != null)
            {
                // 通过控件 Name 或 Command 类型名匹配
                if (topLevel.Name == name || topLevel.Name == fullName ||
                    commandSource.Command.GetType().Name == name || commandSource.Command.GetType().Name == fullName)
                    return commandSource.Command;
            }

            // 3. 递归子控件
            foreach (var child in topLevel.GetVisualChildren())
            {
                if (child is Control c)
                {
                    return GetICommand(c, name);
                }
            }

            return null;
        }
        public static IDisposable SetICommand(this Control topLevel, ICommand command, KeyGesture? keyGesture = null, AvaloniaProperty? targetProperty = null)
        {
            var disposables = new CompositeDisposable();

            // 1. 监听 targetProperty 的值变化,执行命令(先 CanExecute)
            if (targetProperty != null)
            {
                var subscription = topLevel.GetObservable(targetProperty)
                    .Subscribe(value =>
                    {
                        if (command.CanExecute(value))
                        {
                            command.Execute(value);
                        }
                    });

                disposables.Add(subscription);
            }

            // 2. 绑定命令
            if (topLevel is ICommandSource commandSource)
            {
                commandSource.SetPropertyValue("Command", command);
            }
            else
            // 3. 否则,尝试添加 KeyBinding
            {
                var keyBinding = new KeyBinding
                {
                    Command = command,
                    Gesture = keyGesture!
                };

                bool exists = topLevel.KeyBindings.Any(kb => kb.Command == command && kb.Gesture == keyGesture);
                if (!exists)
                {
                    topLevel.KeyBindings.Add(keyBinding);
                }
                else
                {
                    Console.WriteLine("SetICommand:命令已存在于控件的 KeyBindings 中,未重复添加。");
                }
            }
            return disposables;
        }
        //Rect转Point[]
        public static Point[] RectToPoints(this Rect rect)
        {
            return new Point[]
            {
                new Point(rect.Left, rect.Top),        // 左上
                new Point(rect.Right, rect.Top),       // 右上
                new Point(rect.Right, rect.Bottom),    // 右下
                new Point(rect.Left, rect.Bottom)      // 左下
            };
        }
        //动态修改MiterLimit
        public static void SetMiterLimit(this Shape shape, double limit)
        {
            var oldPen = shape.GetFieldValue<IPen>("_strokePen");

            // 创建新的 ImmutablePen
            if (oldPen != null)
            {
                var newPen = new ImmutablePen(
                    oldPen.Brush as IImmutableBrush,
                    oldPen.Thickness,
                    oldPen.DashStyle as ImmutableDashStyle,
                    oldPen.LineCap,
                    oldPen.LineJoin,
                    limit
                );

                // 替换 _strokePen
                shape.SetFieldValue("_strokePen", newPen);
                shape.InvalidateVisual(); // 刷新显示
            }
        }
        //动态加载资源或者样式
        public static void Load(this Control topLevel, string path)
        {
            var uri = new Uri(path, UriKind.RelativeOrAbsolute);

            // 尝试作为 ResourceInclude 加入 Resources.MergedDictionaries
            bool alreadyResource = topLevel.Resources.MergedDictionaries
                .OfType<ResourceInclude>()
                .Any(r => r.Source == uri);

            if (!alreadyResource)
            {
                var include = new ResourceInclude(uri)
                {
                    Source = uri
                };

                try
                {
                    topLevel.Resources.MergedDictionaries.Add(include);
                }
                catch
                {
                    // 不是 ResourceDictionary,尝试作为 Styles
                    bool alreadyStyle = topLevel.Styles
                        .OfType<StyleInclude>()
                        .Any(s => s.Source == uri);

                    if (!alreadyStyle)
                    {
                        var styleInclude = new StyleInclude(uri)
                        {
                            Source = uri
                        };
                        topLevel.Styles.Add(styleInclude);
                    }
                }
            }
        }
        public static void LayoutTransform(this Control topLevel)
        {
            if (topLevel == null)
            {
                Console.WriteLine($"{nameof(topLevel)}不能为空");
                return;
            }

            // 找到父容器
            var parent = topLevel.Parent as Panel;
            if (parent == null)
                return;

            // 找到控件在父容器中的位置
            var index = parent.Children.IndexOf(topLevel);
            if (index < 0)
                return;

            // 从父容器移除原控件
            parent.Children.RemoveAt(index);
            parent.Children.Insert(index, new LayoutTransformControl
            {
                Child = topLevel
            });
        }
    }
}

Reflection.cs代码

using System;
using System.Linq;
using System.Reflection;

namespace Shares
{
    public static class Reflection
    {
        public static T? GetPropertyValue<T>(this object obj, string propertyName)
        {
            if (obj == null)
            {
                Console.WriteLine("GetPropertyValue:传入对象为 null");
                return default;
            }

            Type? type = obj.GetType();
            PropertyInfo? prop = null;

            while (type != null)
            {
                prop = type.GetProperty(propertyName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                if (prop != null)
                    break;
                type = type.BaseType;
            }

            if (prop == null)
            {
                Console.WriteLine($"未找到属性 '{propertyName}',类型链中没有该属性");
                return default;
            }

            var value = prop.GetValue(obj);
            if (value is T t)
                return t;

            try
            {
                return (T?)Convert.ChangeType(value, typeof(T));
            }
            catch
            {
                Console.WriteLine($"属性 '{propertyName}' 类型不匹配。期望 {typeof(T).FullName},实际 {value?.GetType().FullName ?? "null"}");
                return default;
            }
        }

        public static bool SetPropertyValue<T>(this object obj, string propertyName, T value)
        {
            if (obj == null)
            {
                Console.WriteLine("SetPropertyValue:目标对象为 null");
                return false;
            }
            if (string.IsNullOrEmpty(propertyName))
            {
                Console.WriteLine("SetPropertyValue:属性名为空");
                return false;
            }

            Type? type = obj.GetType();
            PropertyInfo? property = null;

            while (type != null)
            {
                property = type.GetProperty(propertyName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                if (property != null)
                    break;
                type = type.BaseType;
            }

            if (property == null)
            {
                Console.WriteLine($"SetPropertyValue:未找到属性 '{propertyName}',类型链中没有该属性");
                return false;
            }
            if (!property.CanWrite)
            {
                Console.WriteLine($"SetPropertyValue:属性 '{propertyName}' 不可写");
                return false;
            }

            try
            {
                property.SetValue(obj, value);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"SetPropertyValue:设置属性 '{propertyName}' 失败,异常:{ex}");
                return false;
            }
        }
        public static T? GetFieldValue<T>(this object obj, string fieldName)
        {
            if (obj == null)
            {
                Console.WriteLine("GetFieldValue:传入对象为 null");
                return default;
            }

            Type? type = obj.GetType();
            FieldInfo? field = null;

            while (type != null)
            {
                field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
                if (field != null)
                    break;

                type = type.BaseType;
            }

            if (field == null)
            {
                Console.WriteLine($"未找到字段 '{fieldName}',类型链中没有该字段");
                return default;
            }

            var value = field.GetValue(obj);
            if (value is T t)
                return t;

            try
            {
                return (T?)Convert.ChangeType(value, typeof(T));
            }
            catch
            {
                Console.WriteLine($"字段 '{fieldName}' 类型不匹配。期望 {typeof(T).FullName},实际 {value?.GetType().FullName ?? "null"}");
                return default;
            }
        }

        public static bool SetFieldValue<T>(this object obj, string fieldName, T value)
        {
            if (obj == null)
            {
                Console.WriteLine("SetFieldValue:目标对象为 null");
                return false;
            }
            if (string.IsNullOrEmpty(fieldName))
            {
                Console.WriteLine("SetFieldValue:字段名为空");
                return false;
            }

            Type? type = obj.GetType();
            FieldInfo? field = null;

            while (type != null)
            {
                field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
                if (field != null)
                    break;
                type = type.BaseType;
            }

            if (field == null)
            {
                Console.WriteLine($"SetFieldValue:未找到字段 '{fieldName}',类型链中没有该字段");
                return false;
            }

            try
            {
                field.SetValue(obj, value);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"SetFieldValue:设置字段 '{fieldName}' 失败,异常:{ex}");
                return false;
            }
        }
        public static object? InvokeMethod(this object obj, string methodName, params object?[]? parameters)
        {
            if (obj == null)
            {
                Console.WriteLine("InvokeMethod:目标对象为 null");
                return null;
            }

            if (string.IsNullOrWhiteSpace(methodName))
            {
                Console.WriteLine("InvokeMethod:方法名为空");
                return null;
            }

            parameters ??= Array.Empty<object?>();
            Type? type = obj.GetType();
            MethodInfo? method = null;

            while (type != null)
            {
                var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
                                  .Where(m => m.Name == methodName);

                foreach (var m in methods)
                {
                    var ps = m.GetParameters();
                    if (ps.Length == parameters.Length)
                    {
                        method = m;
                        break;
                    }
                }

                if (method != null)
                    break;

                type = type.BaseType;
            }

            if (method == null)
            {
                Console.WriteLine($"InvokeMethod:未找到方法 '{methodName}',参数个数:{parameters.Length}");
                return null;
            }

            try
            {
                var result = method.Invoke(obj, parameters);
                return method.ReturnType == typeof(void) ? null : result;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"InvokeMethod:调用 '{methodName}' 异常:{ex.Message}");
                return null;
            }
        }

        public static T? InvokeMethod<T>(this object obj, string methodName, params object?[]? parameters)
        {
            var result = obj.InvokeMethod(methodName, parameters);
            return result is T t ? t : default;
        }
    }
}

CompilerService.cs代码 

using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;

namespace Shares.Avalonia
{
    public static class CompilerService
    {
        public static bool IsBrowser()
        {
            return RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
        }
        private static PortableExecutableReference[]? s_references;

        public static string? BaseUri { get; set; }

        private static async Task LoadReferences()
        {
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();

            if (IsBrowser())
            {
                if (BaseUri is null)
                {
                    return;
                }

                var appDomainReferences = new List<PortableExecutableReference>();
                var client = new HttpClient
                {
                    BaseAddress = new Uri(BaseUri)
                };

                Console.WriteLine($"Loading references BaseUri: {BaseUri}");

                foreach (var reference in assemblies.Where(x => !x.IsDynamic))
                {
                    try
                    {
                        var name = reference.GetName().Name;
                        var requestUri = $"{BaseUri}managed/{name}.dll";
                        Console.WriteLine($"Loading reference requestUri: {requestUri}, FullName: {reference.FullName}");
                        var stream = await client.GetStreamAsync(requestUri);
                        appDomainReferences.Add(MetadataReference.CreateFromStream(stream));
                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception);
                    }
                }

                s_references = appDomainReferences.ToArray();
            }
            else
            {
                var appDomainReferences = new List<PortableExecutableReference>();

                foreach (var reference in assemblies.Where(x => !x.IsDynamic && !string.IsNullOrWhiteSpace(x.Location)))
                {
                    appDomainReferences.Add(MetadataReference.CreateFromFile(reference.Location));
                }

                s_references = appDomainReferences.ToArray();
            }
        }

        public static async Task<(Assembly? Assembly, AssemblyLoadContext? Context)> GetScriptAssembly(string code)
        {
            if (s_references is null)
            {
                await LoadReferences();
            }

            var stringText = SourceText.From(code, Encoding.UTF8);
            var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest);
            var parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(stringText, parseOptions);
            var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithOptimizationLevel(OptimizationLevel.Release);
            var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), new[] { parsedSyntaxTree }, s_references, compilationOptions);

            using var ms = new MemoryStream();
            var result = compilation.Emit(ms);
            var errors = result.Diagnostics.Where(x => x.Severity == DiagnosticSeverity.Error);
            if (!result.Success)
            {
                foreach (var error in errors)
                {
                    Console.WriteLine(error);
                }

                return (null, null);
            }

            ms.Seek(0, SeekOrigin.Begin);

            var context = new AssemblyLoadContext(name: Path.GetRandomFileName(), isCollectible: true);
            var assembly = context.LoadFromStream(ms);

            return (assembly, context);
        }

        public static async Task<(Assembly? Assembly, AssemblyLoadContext? Context)> GetScriptAssembly(Dictionary<string, string> sourceFiles)
        {
            if (s_references is null)
                await LoadReferences();

            var syntaxTrees = new List<SyntaxTree>();
            var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest);

            foreach (var kv in sourceFiles)
            {
                var sourceText = SourceText.From(kv.Value, Encoding.UTF8);
                var syntaxTree = SyntaxFactory.ParseSyntaxTree(sourceText, parseOptions, path: kv.Key);
                syntaxTrees.Add(syntaxTree);
            }

            var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
                .WithOptimizationLevel(OptimizationLevel.Release);

            var compilation = CSharpCompilation.Create(
                assemblyName: Path.GetRandomFileName(),
                syntaxTrees: syntaxTrees,
                references: s_references,
                options: compilationOptions
            );

            using var ms = new MemoryStream();
            var result = compilation.Emit(ms);

            if (!result.Success)
            {
                foreach (var diag in result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error))
                    Console.WriteLine(diag);
                return (null, null);
            }

            ms.Seek(0, SeekOrigin.Begin);
            var context = new AssemblyLoadContext(Path.GetRandomFileName(), isCollectible: true);
            var assembly = context.LoadFromStream(ms);
            return (assembly, context);
        }
    }
}
posted on 2025-07-08 14:10  dalgleish  阅读(134)  评论(0)    收藏  举报