Reflect_Proxy.cs 14.3 KB
Newer Older
潘栩锋's avatar
潘栩锋 committed
1 2 3 4 5 6 7 8 9 10
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace FObjBase.Reflect
{
潘栩锋's avatar
潘栩锋 committed
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
    /// <summary>
    /// obj 服务代理;
    /// 1.如果代理的对象为 INotifyPropertyChanged, 对象内的 property 改变,能推送给客户端( [JsonIgnore] 除外);
    /// 2.代理的对象不为INotifyPropertyChanged, 但 对象内的 property 
    ///     a.是 [PropertyPush], 
    ///     b.且是 INotifyPropertyChanged, 
    ///     c.且 只能是get,不能有set,
    /// 那这个 property 内的 子property 改变,也会推送给 客户端 且 子property 是 [PropertyPush],会继续向下全部注册 PropertyChanged,
    /// 也推送给 客户端;
    /// 3. 客户端 可以通过 Call(.....) 调用 服务 的function,  function返回的内容,需要通过[Call(...)] 定义; 且function 必须是
    /// void function(object param1, object param2,object paramN, AsyncCBHandler asyncDelegate, object asyncContext);
    /// 必须有参数 AsyncCBHandler asyncDelegate, object asyncContext, 名字不能改。 前面的 param1~paramN, 多少个都行
    /// 4. 服务中的event, 通过 [Push(...)] 可以推送给客户端, 但event 只能是 EventHandler
    /// [Push(typeof(BulkDBTempFrameChangedEventArgs))]
    ///  public event EventHandler TempFrameChanged;
    ///  
    /// </summary>
潘栩锋's avatar
潘栩锋 committed
28 29
    public class Reflect_Proxy : FObj
    {
30 31 32 33
        #region Core
        /// <summary>
        /// 对象的接口类型
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
34
        Type interfaceType;
35 36 37
        /// <summary>
        /// 代理对象
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
38
        object obj;
39 40 41
        /// <summary>
        /// 忽略设置
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
42
        public bool ignoreSet = false;
43 44 45
        /// <summary>
        /// 对象的全部event
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
46
        List<AnyEvent> anyEvents = new List<AnyEvent>();
47 48 49 50 51 52 53
        /// <summary>
        /// [PropertyPush] 标签树 
        /// </summary>
        SubPropertyNode rootNode;
        /// <summary>
        /// interfaceType 及其父类 的全部属性
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
54
        List<string> properties = new List<string>();
55 56
        #endregion

潘栩锋's avatar
潘栩锋 committed
57 58 59 60

        public Reflect_Proxy(int objsys_idx, UInt32 id, Type interfaceType, object obj) : base(objsys_idx)
        {
            ID = id;
61 62
            Init(interfaceType, obj);
        }
潘栩锋's avatar
潘栩锋 committed
63

64 65 66
        #region Core
        public void Init(Type interfaceType, object obj)
        {
潘栩锋's avatar
潘栩锋 committed
67 68 69
            this.interfaceType = interfaceType;
            this.obj = obj;

70 71 72 73 74 75
            rootNode = new SubPropertyNode
            {
                Obj = obj,
                InterfaceType = interfaceType,
                SubPropertyChanged = Sub_PropertyChanged
            };
潘栩锋's avatar
潘栩锋 committed
76 77

            //注册 obj 的PropertyChanged 事件,获取 interfaceType 全部属性名称,包括它的父类的全部属性名称
潘栩锋's avatar
潘栩锋 committed
78 79 80
            InitPropertyChanged();

            //处理[PropertyPush]
81
            COMMON.InitPropertyPush(rootNode);
潘栩锋's avatar
潘栩锋 committed
82 83 84 85

            //处理[Push]
            InitEventPush();
        }
86
        void InitPropertyChanged()
潘栩锋's avatar
潘栩锋 committed
87 88 89 90 91
        {
            if (!typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
                return;

            //继承了INotifyPropertyChanged
92
            ((INotifyPropertyChanged)(this.obj)).PropertyChanged += rootNode.PropertyChanged;
潘栩锋's avatar
潘栩锋 committed
93

94 95 96 97
            var propertyInfos = COMMON.GetAllPropertyInfos(this.interfaceType);//获取全部属性, 包括父类的属性

            foreach (var propertyInfo in propertyInfos)
            {
潘栩锋's avatar
潘栩锋 committed
98 99 100 101

                if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() != null)
                    continue;//这个不需要推送

102
                if (properties.Contains(propertyInfo.Name))
潘栩锋's avatar
潘栩锋 committed
103 104 105 106
                    continue;
                properties.Add(propertyInfo.Name);
            }
        }
潘栩锋's avatar
潘栩锋 committed
107

108
        void InitEventPush()
潘栩锋's avatar
潘栩锋 committed
109 110 111 112 113 114 115 116
        {
            var interfaceTypes = new List<Type>();

            interfaceTypes.Add(this.interfaceType);
            interfaceTypes.AddRange(this.interfaceType.GetInterfaces());


            var eventInfos = new List<EventInfo>();
117 118
            foreach (var ifaceType in interfaceTypes)
            {
潘栩锋's avatar
潘栩锋 committed
119 120
                eventInfos.AddRange(ifaceType.GetEvents());
            }
121

潘栩锋's avatar
潘栩锋 committed
122 123 124 125 126 127 128 129 130 131 132 133
            foreach (var eventInfo in eventInfos)
            {
                var pushAttribute = eventInfo.GetCustomAttribute<PushAttribute>();
                if (pushAttribute == null)
                    continue;

                if (anyEvents.Any(ae => ae.eventName == eventInfo.Name))
                    continue;//已经添加了

                var anyEvent = new AnyEvent()
                {
                    eventName = eventInfo.Name,
134
                    PushObjInfoEx = (rd) => reponse_PushObjInfoEx(rd, true)
潘栩锋's avatar
潘栩锋 committed
135 136 137 138 139 140 141
                };
                //这个事件需要推送
                eventInfo.AddEventHandler(obj, anyEvent.eventHandler);
                anyEvents.Add(anyEvent);

            }
        }
142 143 144 145 146
        void Sub_PropertyChanged(SubPropertyNode node, PropertyChangedEventArgs e)
        {
            //if (ignoreSet)//从服务器接收的数据,不用再推送给服务器
            //    return;
            var type = node.Obj.GetType();
潘栩锋's avatar
潘栩锋 committed
147

148 149 150
            var propertyInfo = type.GetProperty(e.PropertyName);
            if (propertyInfo == null)
                return;//获取失败!!!
潘栩锋's avatar
潘栩锋 committed
151

152 153
            if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() != null)
                return;//这个不需要推送
潘栩锋's avatar
潘栩锋 committed
154

155 156 157 158 159 160
            var v = propertyInfo.GetValue(node.Obj);
            var jObject = new JObject();
            if (v == null)
                jObject.Add(propertyInfo.Name, null);
            else
                jObject.Add(propertyInfo.Name, JToken.FromObject(v));
潘栩锋's avatar
潘栩锋 committed
161

162
            var rData = new Reflect_OBJ_INTERFACE.ReflectData
潘栩锋's avatar
潘栩锋 committed
163
            {
164 165 166 167
                name = COMMON.GetNodePath(node),
                data = jObject
            };
            reponse_PushObjInfoEx(rData, false);
潘栩锋's avatar
潘栩锋 committed
168 169
        }

170
        Reflect_OBJ_INTERFACE.ReflectData request_CALL_GetAllProperties()
潘栩锋's avatar
潘栩锋 committed
171
        {
172 173 174 175 176 177

            var jObject = new JObject();

            var type = obj.GetType();

            foreach (var propertyName in properties)
潘栩锋's avatar
潘栩锋 committed
178
            {
179 180 181 182 183 184
                var propertyInfo = type.GetProperty(propertyName);
                var v = propertyInfo.GetValue(obj);
                if (v == null)
                    jObject.Add(propertyInfo.Name, null);
                else
                    jObject.Add(propertyInfo.Name, JToken.FromObject(v));
潘栩锋's avatar
潘栩锋 committed
185 186
            }

187 188 189 190 191
            var rData = new Reflect_OBJ_INTERFACE.ReflectData
            {
                data = jObject
            };
            return rData;
潘栩锋's avatar
潘栩锋 committed
192 193
        }

194
        void request_CALL_SetProperty(Reflect_OBJ_INTERFACE.ReflectData rData)
潘栩锋's avatar
潘栩锋 committed
195
        {
196
            //ignoreSet = true;
潘栩锋's avatar
潘栩锋 committed
197

198 199 200 201 202 203
            //sub property
            var node = COMMON.FindNode(rootNode, rData.name);
            if (node == null)
            {
                //异常
                //客户端乱发过来
潘栩锋's avatar
潘栩锋 committed
204
                return;
205
            }
潘栩锋's avatar
潘栩锋 committed
206

207 208
            string json = rData.data.ToString();
            JsonConvert.PopulateObject(json, node.Obj);
潘栩锋's avatar
潘栩锋 committed
209

210
            //ignoreSet = false;
潘栩锋's avatar
潘栩锋 committed
211 212
        }

213
        void request_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
潘栩锋's avatar
潘栩锋 committed
214
        {
215 216 217 218 219 220 221
            var type = obj.GetType();
            var paramNames_req = rData.data.Children().OfType<JProperty>().Select(p => p.Name);
            MethodInfo methodInfo = GetMethodInfo(type, rData.name, paramNames_req);
            if (methodInfo == null)
            {
                //不能找到,
                throw new Exception($"程序写错了, 不能找到 rData.name={rData.name} 或者 参数名称不对,没法完全匹配");
潘栩锋's avatar
潘栩锋 committed
222 223
            }

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
            var parameterInfos = methodInfo.GetParameters();
            object[] parameters = new object[parameterInfos.Count()];
            for (int i = 0; i < parameters.Count(); i++)
            {
                var ptype = parameterInfos[i].ParameterType;
                var pname = parameterInfos[i].Name;
                if (string.Compare(pname, Reflect_OBJ_INTERFACE.asyncDelegate, true) == 0)
                {
                    parameters[i] = new AsyncCBHandler(asyncDelegate);
                }
                else if (string.Compare(pname, Reflect_OBJ_INTERFACE.asyncContext, true) == 0)
                {
                    cc.methodName = rData.name;
                    parameters[i] = cc;
                }
                else
                {
                    parameters[i] = rData.data[pname].ToObject(ptype);
                }
            }
            methodInfo.Invoke(obj, parameters);
潘栩锋's avatar
潘栩锋 committed
245 246
        }

247
        void asyncDelegate(object asyncContext, object retData)
潘栩锋's avatar
潘栩锋 committed
248
        {
249 250 251
            var cc = (CC)asyncContext;

            var rData = new Reflect_OBJ_INTERFACE.ReflectData()
潘栩锋's avatar
潘栩锋 committed
252
            {
253 254 255
                name = cc.methodName,
                data = retData == null ? null : JToken.FromObject(retData)
            };
潘栩锋's avatar
潘栩锋 committed
256

257
            reponse_CALL_MethodInvoke(rData, cc);
潘栩锋's avatar
潘栩锋 committed
258
        }
259 260

        MethodInfo GetMethodInfo(Type type, string name, IEnumerable<string> parameterNames)
261
        {
262

263
            var methodInfos = from mi in type.GetMethods() where mi.Name == name select mi;
264
            if (methodInfos.Count() == 0)
265 266 267 268 269 270 271 272
                return null;
            if (methodInfos.Count() == 1)
                return methodInfos.First();

            //必须完全匹配
            foreach (var methodInfo in methodInfos)
            {
                var parameterInfos = methodInfo.GetParameters();
273 274 275
                //全部参数名称
                var names = parameterInfos.Select(pi => pi.Name).ToList();
                //删除掉 asyncDelegate,asyncContext
276 277
                names.Remove(Reflect_OBJ_INTERFACE.asyncDelegate);
                names.Remove(Reflect_OBJ_INTERFACE.asyncContext);
278

279 280
                var names_req = parameterNames;

281 282 283 284 285 286 287 288 289 290 291
                if (names.Count() != names_req.Count())
                    continue;//数量不一致,肯定不同

                var sames = names_req.Intersect(names);

                if (sames.Count() != names_req.Count())
                    continue;// names 与 names_req 的交集数量与names_req不一样,肯定不同

                //就是它
                return methodInfo;

292 293 294
            }
            return null;
        }
295 296

        public void Dispose()
潘栩锋's avatar
潘栩锋 committed
297
        {
298
            if (typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
潘栩锋's avatar
潘栩锋 committed
299
            {
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
                //继承了INotifyPropertyChanged
                ((INotifyPropertyChanged)(this.obj)).PropertyChanged -= rootNode.PropertyChanged;
            }

            //释放subProperties
            COMMON.NodeDispose(rootNode);
        }
        #endregion


        void reponse_PushObjInfoEx(Reflect_OBJ_INTERFACE.ReflectData rData, bool isEvent)
        {
            //数据推送!!!
            //再嵌套
            var pkgName = isEvent ? Reflect_OBJ_INTERFACE.PUSH_Event : Reflect_OBJ_INTERFACE.PUSH_PropertyChanged;
潘栩锋's avatar
潘栩锋 committed
315

316 317 318 319 320 321 322 323 324
            string json = JsonConvert.SerializeObject(rData);

            CurrObjSys.PushObjInfoEx(this,
                pkgName,
                Misc.Converter.StringToBytes(json));
        }

        void reponse_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
        {
潘栩锋's avatar
潘栩锋 committed
325 326
            string json = JsonConvert.SerializeObject(rData);
            CurrObjSys.PushCallFunctionEx(
327
                cc.from, cc.srcid, ID, cc.magic,
潘栩锋's avatar
潘栩锋 committed
328 329 330
                Reflect_OBJ_INTERFACE.CALL_MethodInvoke,
                Misc.Converter.StringToBytes(json));
        }
331 332 333 334 335 336

        void reponse_CALL_GetAllProperties(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
        {
            string json = JsonConvert.SerializeObject(rData);

            CurrObjSys.PushCallFunctionEx(
337 338
                cc.from, cc.srcid, ID, cc.magic,
                Reflect_OBJ_INTERFACE.CALL_GetAllProperties,
339 340 341 342 343 344 345 346 347 348 349
                Misc.Converter.StringToBytes(json));
        }

        public override void CallFunction(IFConn from, uint srcid, uint magic, ushort funcid, byte[] infodata)
        {
            switch (funcid)
            {
                case Reflect_OBJ_INTERFACE.CALL_GetAllProperties:
                    {
                        var rData = request_CALL_GetAllProperties();

350
                        reponse_CALL_GetAllProperties(rData, new CC() { from = from, srcid = srcid, magic = magic });
351 352
                    }
                    break;
353

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
                case Reflect_OBJ_INTERFACE.CALL_SetProperty:
                    {
                        string json = Misc.Converter.BytesToString(infodata);
                        var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);

                        request_CALL_SetProperty(rData);
                    }
                    break;

                case Reflect_OBJ_INTERFACE.CALL_MethodInvoke:
                    {
                        string json = Misc.Converter.BytesToString(infodata);
                        var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);

                        request_CALL_MethodInvoke(rData, new CC() { from = from, srcid = srcid, magic = magic });
                    }
                    break;
            }
        }

潘栩锋's avatar
潘栩锋 committed
374 375 376 377 378
        class CC
        {
            public IFConn from;
            public UInt32 srcid;
            public UInt32 magic;
379 380 381 382

            /// <summary>
            /// CALL_MethodInvoke 时使用
            /// </summary>
潘栩锋's avatar
潘栩锋 committed
383 384 385
            public string methodName;
        }
    }
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417

    /// <summary>
    /// 事件推送包装
    /// </summary>
    class AnyEvent
    {
        /// <summary>
        /// 事件名称
        /// </summary>
        public string eventName;
        /// <summary>
        /// json包装后的ReflectData 推送
        /// </summary>
        public Action<Reflect_OBJ_INTERFACE.ReflectData> PushObjInfoEx;
        /// <summary>
        /// 给 EventInfo 调用
        /// </summary>
        public EventHandler eventHandler;
        public AnyEvent()
        {
            eventHandler = new EventHandler(Obj_AnyEvent);
        }
        void Obj_AnyEvent(object sender, EventArgs e)
        {
            var rData = new Reflect_OBJ_INTERFACE.ReflectData()
            {
                name = eventName,
                data = JObject.FromObject(e)
            };
            PushObjInfoEx?.Invoke(rData);
        }
    }
潘栩锋's avatar
潘栩锋 committed
418
}