alielie
7 天以前 e57938fbda9bff702004038f76d009422968bff5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using System.Reflection;
 
namespace DeviceService.Driver
{
    /// <summary>
    /// 基于 DispatchProxy 的驱动动态代理(.NET Framework 4.7.1+ 内置 API)。
    ///
    /// 用法:宿主自定义一个"鸭子接口"(方法名、参数类型与驱动方法一一对应),
    /// 驱动无需实现该接口、无需引用宿主程序集。接口调用按"方法名 + 参数个数"
    /// 匹配到驱动方法,经 <see cref="DriverInstance"/>(MBR 透明代理)转发到
    /// 驱动所在的 AppDomain 内反射执行。
    ///
    /// 与 RealProxy 的区别:
    /// - 生成的代理是宿主域内的普通对象,不再有 Remoting 相关的怪异行为
    ///   (Object.GetType/ToString 等基类方法不会被误路由,无需拦截);
    /// - out/ref 参数通过直接改写 args 数组回填;
    /// - 异常直接抛出,不再经过 ReturnMessage 包装;
    /// - API 在 .NET Core / .NET 5+ 同样可用,宿主未来升级可无缝迁移。
    ///
    /// 约束:s
    /// - T 必须是接口(DispatchProxy 只针对接口生成代理类);
    /// - 接口方法的参数/返回值必须可跨域封送(基元类型、string、[Serializable] DTO)。
    /// </summary>
    // 注意:不能 sealed —— DispatchProxy 在运行时生成其派生类作为代理类型
    public class DriverDispatchProxy : DispatchProxy
    {
        private DriverInstance _instance;
 
        /// <summary>
        /// 创建实现 T 的驱动动态代理(T 为宿主自定义的鸭子接口)。
        /// </summary>
        public static T Create<T>(DriverInstance instance) where T : class
        {
            if (!typeof(T).IsInterface)
            {
                throw new ArgumentException(
                    $"T 必须是接口(驱动类型不可跨域封送,宿主也无法引用厂商程序集),实际为 {typeof(T)}",
                    nameof(T));
            }
 
            // DispatchProxy.Create<T, TProxy> 要求 TProxy 为非泛型类,
            // 因此代理实例的创建与状态注入分两步完成
            var proxy = (DriverDispatchProxy)(object)Create<T, DriverDispatchProxy>();
            proxy._instance = instance;
            return (T)(object)proxy;
        }
 
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            if (targetMethod == null)
            {
                throw new NotSupportedException("无法解析接口方法(可能由泛型方法调用引起)");
            }
 
            var mi = _instance.GetMethods().FirstOrDefault(m =>
                string.Equals(m.Name, targetMethod.Name, StringComparison.Ordinal)
                && m.ParameterCount == (args?.Length ?? 0));
 
            if (mi == null)
            {
                throw new MissingMethodException(_instance.TypeFullName, $"{targetMethod.Name}({args?.Length ?? 0} 参数)——驱动未提供同名且参数个数一致的方法");
            }
 
            var direct = _instance.InvokeDirect(mi.Index, args);
            if (!direct.Success)
            {
                throw new InvalidOperationException($"驱动方法 {targetMethod.Name} 执行失败: {direct.Error}");
            }
 
            // out/ref 回填:把驱动域内的回填值写回 args 数组,
            // DispatchProxy 会自动同步回调用方的 out/ref 变量
            if (direct.ArgsOut != null && args != null)
            {
                var count = Math.Min(args.Length, direct.ArgsOut.Length);
                for (var i = 0; i < count; i++)
                {
                    args[i] = direct.ArgsOut[i];
                }
            }
 
            return direct.Value;
        }
    }
}