using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using System.ServiceModel.Security; using System.Text; using System.Threading.Tasks; namespace FObjBase.Reflect { public class Reflect_Proxy : FObj { Type interfaceType; object obj; public bool ignoreSet = false; List anyEvents = new List(); Dictionary subProperties = new Dictionary(); List properties = new List(); public Reflect_Proxy(int objsys_idx, UInt32 id, Type interfaceType, object obj) : base(objsys_idx) { ID = id; this.interfaceType = interfaceType; this.obj = obj; InitPropertyChanged(); //处理[PropertyPush] InitPropertyPush(); //处理[Push] InitEventPush(); } void InitPropertyChanged() { if (!typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType)) return; //继承了INotifyPropertyChanged ((INotifyPropertyChanged)(this.obj)).PropertyChanged += Obj_PropertyChanged; var interfaceTypes = new List(); interfaceTypes.Add(this.interfaceType); interfaceTypes.AddRange(this.interfaceType.GetInterfaces()); var propertyInfos = new List(); foreach (var ifaceType in interfaceTypes) { propertyInfos.AddRange(ifaceType.GetProperties()); } foreach (var propertyInfo in propertyInfos) { if (propertyInfo.GetCustomAttribute() != null) continue;//这个不需要推送 if (properties.Contains(propertyInfo.Name)) continue; properties.Add(propertyInfo.Name); } } void InitEventPush() { var interfaceTypes = new List(); interfaceTypes.Add(this.interfaceType); interfaceTypes.AddRange(this.interfaceType.GetInterfaces()); var eventInfos = new List(); foreach (var ifaceType in interfaceTypes) { eventInfos.AddRange(ifaceType.GetEvents()); } foreach (var eventInfo in eventInfos) { var pushAttribute = eventInfo.GetCustomAttribute(); if (pushAttribute == null) continue; if (anyEvents.Any(ae => ae.eventName == eventInfo.Name)) continue;//已经添加了 var anyEvent = new AnyEvent() { eventName = eventInfo.Name, PushObjInfoEx = (msg) => { var buf = Misc.Converter.StringToBytes(msg); CurrObjSys.PushObjInfoEx( this, Reflect_OBJ_INTERFACE.PUSH_Event, buf); } }; //这个事件需要推送 eventInfo.AddEventHandler(obj, anyEvent.eventHandler); anyEvents.Add(anyEvent); } } void InitPropertyPush() { //处理[PropertyPush] var interfaceTypes = new List(); interfaceTypes.Add(this.interfaceType); interfaceTypes.AddRange(this.interfaceType.GetInterfaces()); var propertyInfos = new List(); foreach (var ifaceType in interfaceTypes) propertyInfos.AddRange(ifaceType.GetProperties()); foreach (var propertyInfo in propertyInfos) { if (!IsPropertyPush(propertyInfo)) continue; if (!properties.Contains(propertyInfo.Name)) { properties.Add(propertyInfo.Name); } InitSubPropertyPush(this.obj.GetType().GetProperty(propertyInfo.Name), this.obj, null); } } bool IsPropertyPush(PropertyInfo propertyInfo) { if (propertyInfo.GetCustomAttribute() == null) return false;//必须是[PropertyPush] if (propertyInfo.CanWrite) return false;//它只能是get,不能有set if (!typeof(INotifyPropertyChanged).IsAssignableFrom(propertyInfo.PropertyType)) return false;//必须是从INotifyPropertyChanged派生的 return true; } void InitSubPropertyPush(PropertyInfo propertyInfo, object obj, string parentName) { //下级推送!!!! var propertyValue = propertyInfo.GetValue(obj); string path = parentName == null ? propertyInfo.Name : $"{parentName}.{propertyInfo.Name}"; subProperties.Add(propertyValue, path); ((INotifyPropertyChanged)(propertyValue)).PropertyChanged += Sub_PropertyChanged; //继续向下找 var subPropertyInfos = propertyInfo.PropertyType.GetProperties(); foreach (var subPropertyInfo in subPropertyInfos) { if (!IsPropertyPush(subPropertyInfo)) continue;//必须是[PropertyPush] InitSubPropertyPush(subPropertyInfo, propertyValue, path); } } class AnyEvent { public string eventName; public Action PushObjInfoEx; 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) }; string reponse = JsonConvert.SerializeObject(rData); PushObjInfoEx?.Invoke(reponse); } } private void Obj_PropertyChanged(object sender, PropertyChangedEventArgs e) { //if (ignoreSet)//从服务器接收的数据,不用再推送给服务器 // return; if (interfaceType == null) return; if (!properties.Contains(e.PropertyName)) return;//这个不需要推送 var v = this.obj.GetType().GetProperty(e.PropertyName).GetValue(sender); var jObject = new JObject(); if(v == null) jObject.Add(e.PropertyName, null); else jObject.Add(e.PropertyName, JToken.FromObject(v)); string json = jObject.ToString(Formatting.None); var buf = Misc.Converter.StringToBytes(json); CurrObjSys.PushObjInfoEx( this, Reflect_OBJ_INTERFACE.PUSH_PropertyChanged, buf); } private void Sub_PropertyChanged(object sender, PropertyChangedEventArgs e) { //if (ignoreSet)//从服务器接收的数据,不用再推送给服务器 // return; if (!subProperties.ContainsKey(sender)) return;//异常, 不是子property var type = sender.GetType(); var propertyInfo = type.GetProperty(e.PropertyName); if (propertyInfo == null) return;//获取失败!!! if (propertyInfo.GetCustomAttribute() != null) return;//这个不需要推送 string path = subProperties[sender]; string[] parentNames = path.Split('.'); if (parentNames.Count() == 0) return;//分解出错 var v = propertyInfo.GetValue(sender); var jObject = new JObject(); if(v == null) jObject.Add(propertyInfo.Name, null); else jObject.Add(propertyInfo.Name, JToken.FromObject(v)); JObject jObject_parent = null; for (int i = 0; i < parentNames.Count(); i++) { int idx = parentNames.Count() - 1 - i; jObject_parent = new JObject(); jObject_parent.Add(parentNames[idx], jObject); jObject = jObject_parent; } string json = jObject_parent.ToString(Formatting.None); CurrObjSys.PushObjInfoEx( this, Reflect_OBJ_INTERFACE.PUSH_PropertyChanged, 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 jObject = new JObject(); var type = obj.GetType(); foreach (var propertyName in properties) { 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)); } string json = jObject.ToString(Formatting.None); CurrObjSys.PushCallFunctionEx(from, srcid, ID, magic, funcid, Misc.Converter.StringToBytes(json)); } break; case Reflect_OBJ_INTERFACE.CALL_SetProperty: { string json = Misc.Converter.BytesToString(infodata); //ignoreSet = true; JsonConvert.PopulateObject(json, obj); //ignoreSet = false; } break; case Reflect_OBJ_INTERFACE.CALL_MethodInvoke: { string json = Misc.Converter.BytesToString(infodata); var rData = JsonConvert.DeserializeObject(json); var type = obj.GetType(); var paramNames_req = rData.data.Children().OfType().Select(p => p.Name); MethodInfo methodInfo = GetMethodInfo(type, rData.name, paramNames_req); if (methodInfo == null) { //不能找到, throw new Exception($"程序写错了, 不能找到 rData.name={rData.name} 或者 参数名称不对,没法完全匹配"); } 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, "asyncDelegate", true) == 0) { parameters[i] = new AsyncCBHandler(asyncDelegate); } else if (string.Compare(pname, "asyncContext", true) == 0) { parameters[i] = new CC { from = from, srcid = srcid, magic = magic, methodName = rData.name }; } else { parameters[i] = rData.data[pname].ToObject(ptype); } } methodInfo.Invoke(obj, parameters); } break; } } MethodInfo GetMethodInfo(Type type, string name, IEnumerable parameterNames) { var methodInfos = from mi in type.GetMethods() where mi.Name == name select mi; if(methodInfos.Count()==0) return null; if (methodInfos.Count() == 1) return methodInfos.First(); //必须完全匹配 foreach (var methodInfo in methodInfos) { var parameterInfos = methodInfo.GetParameters(); //全部参数名称 var names = parameterInfos.Select(pi => pi.Name).ToList(); //删除掉 asyncDelegate,asyncContext names.Remove("asyncDelegate"); names.Remove("asyncContext"); var names_req = parameterNames; 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; } return null; } void asyncDelegate(object asyncContext, object retData) { var cc = (CC)asyncContext; var rData = new Reflect_OBJ_INTERFACE.ReflectData() { name = cc.methodName, data = retData==null?null:JToken.FromObject(retData) }; string json = JsonConvert.SerializeObject(rData); CurrObjSys.PushCallFunctionEx( cc.from, cc.srcid, ID, cc.magic, Reflect_OBJ_INTERFACE.CALL_MethodInvoke, Misc.Converter.StringToBytes(json)); } class CC { public IFConn from; public UInt32 srcid; public UInt32 magic; public string methodName; } } }