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
{
///
/// 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;
///
///
public class Reflect_Proxy : FObj
{
#region Core
///
/// 对象的接口类型
///
Type interfaceType;
///
/// 代理对象
///
object obj;
///
/// 忽略设置
///
public bool ignoreSet = false;
///
/// 对象的全部event
///
List anyEvents = new List();
///
/// [PropertyPush] 标签树
///
SubPropertyNode rootNode;
///
/// interfaceType 及其父类 的全部属性
///
List properties = new List();
#endregion
public Reflect_Proxy(int objsys_idx, UInt32 id, Type interfaceType, object obj) : base(objsys_idx)
{
ID = id;
Init(interfaceType, obj);
}
#region Core
public void Init(Type interfaceType, object obj)
{
this.interfaceType = interfaceType;
this.obj = obj;
rootNode = new SubPropertyNode
{
Obj = obj,
InterfaceType = interfaceType,
SubPropertyChanged = Sub_PropertyChanged
};
//注册 obj 的PropertyChanged 事件,获取 interfaceType 全部属性名称,包括它的父类的全部属性名称
InitPropertyChanged();
//处理[PropertyPush]
COMMON.InitPropertyPush(rootNode);
//处理[Push]
InitEventPush();
}
void InitPropertyChanged()
{
if (!typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
return;
//继承了INotifyPropertyChanged
((INotifyPropertyChanged)(this.obj)).PropertyChanged += rootNode.PropertyChanged;
var propertyInfos = COMMON.GetAllPropertyInfos(this.interfaceType);//获取全部属性, 包括父类的属性
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 = (rd) => reponse_PushObjInfoEx(rd, true)
};
//这个事件需要推送
eventInfo.AddEventHandler(obj, anyEvent.eventHandler);
anyEvents.Add(anyEvent);
}
}
void Sub_PropertyChanged(SubPropertyNode node, PropertyChangedEventArgs e)
{
//if (ignoreSet)//从服务器接收的数据,不用再推送给服务器
// return;
var type = node.Obj.GetType();
var propertyInfo = type.GetProperty(e.PropertyName);
if (propertyInfo == null)
return;//获取失败!!!
if (propertyInfo.GetCustomAttribute() != null)
return;//这个不需要推送
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));
var rData = new Reflect_OBJ_INTERFACE.ReflectData
{
name = COMMON.GetNodePath(node),
data = jObject
};
reponse_PushObjInfoEx(rData, false);
}
Reflect_OBJ_INTERFACE.ReflectData request_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));
}
var rData = new Reflect_OBJ_INTERFACE.ReflectData
{
data = jObject
};
return rData;
}
void request_CALL_SetProperty(Reflect_OBJ_INTERFACE.ReflectData rData)
{
//ignoreSet = true;
//sub property
var node = COMMON.FindNode(rootNode, rData.name);
if (node == null)
{
//异常
//客户端乱发过来
return;
}
string json = rData.data.ToString();
JsonConvert.PopulateObject(json, node.Obj);
//ignoreSet = false;
}
void request_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
{
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, 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);
}
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)
};
reponse_CALL_MethodInvoke(rData, cc);
}
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(Reflect_OBJ_INTERFACE.asyncDelegate);
names.Remove(Reflect_OBJ_INTERFACE.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;
}
public void Dispose()
{
if (typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
{
//继承了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;
string json = JsonConvert.SerializeObject(rData);
CurrObjSys.PushObjInfoEx(this,
pkgName,
Misc.Converter.StringToBytes(json));
}
void reponse_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
{
string json = JsonConvert.SerializeObject(rData);
CurrObjSys.PushCallFunctionEx(
cc.from, cc.srcid, ID, cc.magic,
Reflect_OBJ_INTERFACE.CALL_MethodInvoke,
Misc.Converter.StringToBytes(json));
}
void reponse_CALL_GetAllProperties(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
{
string json = JsonConvert.SerializeObject(rData);
CurrObjSys.PushCallFunctionEx(
cc.from, cc.srcid, ID, cc.magic,
Reflect_OBJ_INTERFACE.CALL_GetAllProperties,
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();
reponse_CALL_GetAllProperties(rData, new CC() { from = from, srcid = srcid, magic = magic });
}
break;
case Reflect_OBJ_INTERFACE.CALL_SetProperty:
{
string json = Misc.Converter.BytesToString(infodata);
var rData = JsonConvert.DeserializeObject(json);
request_CALL_SetProperty(rData);
}
break;
case Reflect_OBJ_INTERFACE.CALL_MethodInvoke:
{
string json = Misc.Converter.BytesToString(infodata);
var rData = JsonConvert.DeserializeObject(json);
request_CALL_MethodInvoke(rData, new CC() { from = from, srcid = srcid, magic = magic });
}
break;
}
}
class CC
{
public IFConn from;
public UInt32 srcid;
public UInt32 magic;
///
/// CALL_MethodInvoke 时使用
///
public string methodName;
}
}
///
/// 事件推送包装
///
class AnyEvent
{
///
/// 事件名称
///
public string eventName;
///
/// json包装后的ReflectData 推送
///
public Action PushObjInfoEx;
///
/// 给 EventInfo 调用
///
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);
}
}
}