Commit aa7d0d93 authored by 潘栩锋's avatar 潘栩锋 🚴

添加 FObjBase.Reflect [PropertyPush] 数组支持

parent 2b68df49
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace FObjBase.Reflect
{
static class COMMON
{
static bool IsPropertyPush(PropertyInfo propertyInfo)
{
if (propertyInfo.GetCustomAttribute<PropertyPushAttribute>() == null)
return false;//必须是[PropertyPush]
if (!typeof(INotifyPropertyChanged).IsAssignableFrom(propertyInfo.PropertyType))
return false;//必须是从INotifyPropertyChanged派生的
return true;
}
/// <summary>
/// 获取全部属性, 包括父类的属性, 可能有重复的
/// </summary>
/// <returns></returns>
public static List<PropertyInfo> GetAllPropertyInfos(Type interfaceType)
{
var interfaceTypes = new List<Type>();
interfaceTypes.Add(interfaceType);
interfaceTypes.AddRange(interfaceType.GetInterfaces());
var propertyInfos = new List<PropertyInfo>();//获取全部属性, 包括父类的属性
foreach (var ifaceType in interfaceTypes)
{
propertyInfos.AddRange(ifaceType.GetProperties());
}
return propertyInfos;
}
public static void InitPropertyPush(SubPropertyNode rootNode)
{
//处理[PropertyPush]
var propertyInfos = GetAllPropertyInfos(rootNode.InterfaceType);
foreach (var propertyInfo in propertyInfos)
{
if (propertyInfo.GetCustomAttribute<PropertyPushAttribute>() == null)
continue;//必须是[PropertyPush]
SubPropertyNode node = new SubPropertyNode();
if (ReInitPropertyPush(node, rootNode.Obj, propertyInfo, rootNode.SubPropertyChanged))
{
node.Parent = rootNode;
rootNode.Children.Add(node);
}
}
}
public static bool ReInitPropertyPush(SubPropertyNode node, object parentObj, PropertyInfo propertyInfo, SubPropertyChangedEventHandler sub_PropertyChanged)
{
var propertyValue = propertyInfo.GetValue(parentObj);
// propertyValue==null 也注册
if (typeof(INotifyPropertyChanged).IsAssignableFrom(propertyInfo.PropertyType))
{
//必须是从INotifyPropertyChanged派生的
node.Name = propertyInfo.Name;
node.InterfaceType = propertyInfo.PropertyType;
node.Obj = propertyValue;
node.SubPropertyChanged = sub_PropertyChanged;
if (node.Obj != null)
{
//下级推送!!!!
((INotifyPropertyChanged)(propertyValue)).PropertyChanged += node.PropertyChanged;
InitSubPropertyPush(propertyValue, node, sub_PropertyChanged);
}
return true;
}
else if (typeof(System.Collections.IList).IsAssignableFrom(propertyInfo.PropertyType))
{
//数组
node.Name = propertyInfo.Name;
node.InterfaceType = propertyInfo.PropertyType;
node.Obj = propertyValue;
node.IsArray = true;
var list = node.Obj as System.Collections.IList;
if (list != null && list.Count > 0)
{
InitSubPropertyPushs(list, node, sub_PropertyChanged);
}
return true;
}
return false;
}
static void InitSubPropertyPush(object obj, SubPropertyNode node, SubPropertyChangedEventHandler sub_PropertyChanged)
{
//继续向下找
var propertyInfos = obj.GetType().GetProperties();
foreach (var propertyInfo in propertyInfos)
{
if (!IsPropertyPush(propertyInfo))
continue;//必须是[PropertyPush]
var element = propertyInfo.GetValue(obj);
var node_sub = new SubPropertyNode()
{
Name = propertyInfo.Name,
InterfaceType = propertyInfo.PropertyType,
Obj = element,
Parent = node,
SubPropertyChanged = sub_PropertyChanged
};
//下级推送!!!!
((INotifyPropertyChanged)(element)).PropertyChanged += node_sub.PropertyChanged;
node.Children.Add(node_sub);
InitSubPropertyPush(element, node_sub, sub_PropertyChanged);
}
}
static void InitSubPropertyPushs(System.Collections.IList list, SubPropertyNode node, SubPropertyChangedEventHandler sub_PropertyChanged)
{
for (int i = 0; i < list.Count; i++)
{
var element = list[i];
if (element == null)
{
//空的。。。
continue;
}
var elementType = element.GetType();
if (!typeof(INotifyPropertyChanged).IsAssignableFrom(elementType))
{
//异常!!!!
continue;
}
var node_sub = new SubPropertyNode()
{
Name = $"[{i}]",
InterfaceType = elementType,
Obj = element,
Parent = node,
SubPropertyChanged = sub_PropertyChanged
};
//下级推送!!!!
((INotifyPropertyChanged)(element)).PropertyChanged += node_sub.PropertyChanged;
node.Children.Add(node_sub);
InitSubPropertyPush(element, node_sub, sub_PropertyChanged);
}
}
public static string GetNodePath(SubPropertyNode node)
{
if (string.IsNullOrEmpty(node.Name))
{
//已经是最上级
return null;
}
StringBuilder sb = new StringBuilder();
sb.Append(node.Name);
while (node.Parent != null)
{
node = node.Parent;
if (string.IsNullOrEmpty(node.Name))
{
//到了最上级
break;
}
sb.Insert(0, node.Name + ".");
}
return sb.ToString();
}
public static SubPropertyNode FindNode(SubPropertyNode rootNode, string path)
{
SubPropertyNode node = null;
if (string.IsNullOrEmpty(path))
return rootNode;
var nodes = rootNode.Children;
//分解路径
string[] names = path.Split('.');
foreach (string name in names)
{
if (string.IsNullOrEmpty(name))
{
//这个不算
continue;
}
node = nodes.Find(n => n.Name == name);
if (node == null)
{
//异常
return null;
}
nodes = node.Children;
}
return node;
}
public static void NodeChildrenDispose(List<SubPropertyNode> nodes)
{
foreach (var node in nodes)
{
NodeDispose(node);
}
}
public static void NodeDispose(SubPropertyNode node)
{
if (!node.IsArray)
{
if (node.Obj != null)
((INotifyPropertyChanged)(node.Obj)).PropertyChanged -= node.PropertyChanged;
}
if (node.Children.Count > 0)
NodeChildrenDispose(node.Children);
node.Children.Clear();
node.Obj = null;
node.Parent = null;
}
/// <summary>
/// 处理因为服务器 修改了 [PropertyPush] 的对象, 需要重新注册推送事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public static void PropertyChanged_reInitPropertyPush(SubPropertyNode node, PropertyChangedEventArgs e)
{
var sub_node = node.Children.Find(n => n.Name == e.PropertyName);
if (sub_node == null)
return;
//这个被修改了
//卸载它
COMMON.NodeDispose(sub_node);
var propertyInfo = node.Obj.GetType().GetProperty(e.PropertyName);
//重新注册
COMMON.ReInitPropertyPush(sub_node, node.Obj, propertyInfo, node.SubPropertyChanged);
}
}
/// <summary>
/// 子属性节点,用于注册 INotifyPropertyChanged
/// </summary>
class SubPropertyNode
{
/// <summary>
/// 下级节点
/// </summary>
public List<SubPropertyNode> Children = new List<SubPropertyNode>();
/// <summary>
/// 上级节点
/// </summary>
public SubPropertyNode Parent;
/// <summary>
/// 节点名称;
/// 正常情况,就是属性的Name;
/// 但,当为数组时, 它的下级就是数组的元素。 元素不是数组的属性。 元素的name为 $"[{序号}]"
/// </summary>
public string Name;
/// <summary>
/// 节点对象
/// </summary>
public object Obj;
/// <summary>
/// 对象的模板接口。默认就是 Obj.GetType()
/// </summary>
public Type InterfaceType;
/// <summary>
/// 是数组
/// </summary>
public bool IsArray;
public PropertyChangedEventHandler PropertyChanged;
public SubPropertyChangedEventHandler SubPropertyChanged;
public SubPropertyNode()
{
PropertyChanged = new PropertyChangedEventHandler(_PropertyChanged);
}
public void _PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//处理[PropertyPush]重新注册问题
COMMON.PropertyChanged_reInitPropertyPush(this, e);
SubPropertyChanged?.Invoke(this, e);
}
}
delegate void SubPropertyChangedEventHandler(SubPropertyNode node, PropertyChangedEventArgs e);
}
......@@ -12,6 +12,7 @@ namespace FObjBase.Reflect
/// </summary>
public class PushAttribute : Attribute
{
public const string DefaultTriggerNameHeader = "Trigger_";
public Type EventArgsType;
public string TriggerName;
public PushAttribute(Type eventArgsType)
......@@ -26,7 +27,7 @@ namespace FObjBase.Reflect
}
/// <summary>
/// 注册远程调用返回类型
/// 注册远程调用返回类型; 回调函数名称只能是 AsyncCBHandler asyncDelegate, object asyncContext
/// </summary>
public class CallAttribute : Attribute
{
......
......@@ -42,6 +42,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CallAttribute.cs" />
<Compile Include="COMMON.cs" />
<Compile Include="Reflect_OBJ_INTERFACE.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Reflect_Proxy.cs" />
......
......@@ -30,74 +30,85 @@ namespace FObjBase.Reflect
/// </summary>
public class Reflect_Proxy : FObj
{
#region Core
/// <summary>
/// 对象的接口类型
/// </summary>
Type interfaceType;
/// <summary>
/// 代理对象
/// </summary>
object obj;
/// <summary>
/// 忽略设置
/// </summary>
public bool ignoreSet = false;
/// <summary>
/// 对象的全部event
/// </summary>
List<AnyEvent> anyEvents = new List<AnyEvent>();
Dictionary<object, string> subProperties = new Dictionary<object, string>();
/// <summary>
/// [PropertyPush] 标签树
/// </summary>
SubPropertyNode rootNode;
/// <summary>
/// interfaceType 及其父类 的全部属性
/// </summary>
List<string> properties = new List<string>();
#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;
if (interfaceType == null)
throw new Exception($"Reflect_Proxy 出错,obj = {obj.GetType()} interfaceType=null");
//if (!interfaceType.IsAssignableFrom(obj.GetType()))
// throw new Exception($"Reflect_Proxy 出错,obj = {obj.GetType()} interfaceType={interfaceType}, obj 非继承于 interfaceType");
rootNode = new SubPropertyNode
{
Obj = obj,
InterfaceType = interfaceType,
SubPropertyChanged = Sub_PropertyChanged
};
//注册 obj 的PropertyChanged 事件,获取 interfaceType 全部属性名称,包括它的父类的全部属性名称
InitPropertyChanged();
//处理[PropertyPush]
InitPropertyPush();
COMMON.InitPropertyPush(rootNode);
//处理[Push]
InitEventPush();
}
void InitPropertyChanged()
void InitPropertyChanged()
{
if (!typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
return;
//继承了INotifyPropertyChanged
((INotifyPropertyChanged)(this.obj)).PropertyChanged += Obj_PropertyChanged;
((INotifyPropertyChanged)(this.obj)).PropertyChanged += rootNode.PropertyChanged;
var propertyInfos = GetAllPropertyInfos();//获取全部属性, 包括父类的属性
var propertyInfos = COMMON.GetAllPropertyInfos(this.interfaceType);//获取全部属性, 包括父类的属性
foreach (var propertyInfo in propertyInfos)
{
//获取全部属性的名称,放入 properties
foreach (var propertyInfo in propertyInfos) {
if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() != null)
continue;//这个不需要推送
if (properties.Contains(propertyInfo.Name))//子类 有与 父类一样的名字的属性,忽略它
if (properties.Contains(propertyInfo.Name))
continue;
properties.Add(propertyInfo.Name);
}
}
/// <summary>
/// 获取全部属性, 包括父类的属性
/// </summary>
/// <returns></returns>
List<PropertyInfo> GetAllPropertyInfos() {
var interfaceTypes = new List<Type>();
interfaceTypes.Add(this.interfaceType);
interfaceTypes.AddRange(this.interfaceType.GetInterfaces());
var propertyInfos = new List<PropertyInfo>();//获取全部属性, 包括父类的属性
foreach (var ifaceType in interfaceTypes)
{
propertyInfos.AddRange(ifaceType.GetProperties());
}
return propertyInfos;
}
void InitEventPush()
void InitEventPush()
{
var interfaceTypes = new List<Type>();
......@@ -106,10 +117,11 @@ namespace FObjBase.Reflect
var eventInfos = new List<EventInfo>();
foreach (var ifaceType in interfaceTypes) {
foreach (var ifaceType in interfaceTypes)
{
eventInfos.AddRange(ifaceType.GetEvents());
}
foreach (var eventInfo in eventInfos)
{
var pushAttribute = eventInfo.GetCustomAttribute<PushAttribute>();
......@@ -122,240 +134,137 @@ namespace FObjBase.Reflect
var anyEvent = new AnyEvent()
{
eventName = eventInfo.Name,
PushObjInfoEx = (msg) => {
var buf = Misc.Converter.StringToBytes(msg);
CurrObjSys.PushObjInfoEx(
this, Reflect_OBJ_INTERFACE.PUSH_Event,
buf);
}
PushObjInfoEx = (rd) => reponse_PushObjInfoEx(rd, true)
};
//这个事件需要推送
eventInfo.AddEventHandler(obj, anyEvent.eventHandler);
anyEvents.Add(anyEvent);
}
}
void InitPropertyPush() {
//处理[PropertyPush]
var propertyInfos = GetAllPropertyInfos();//获取全部属性, 包括父类的属性
foreach (var propertyInfo in propertyInfos)
{
if (!IsPropertyPush(propertyInfo))
continue;
if (!properties.Contains(propertyInfo.Name)) {
properties.Add(propertyInfo.Name);
}
//这个属性可能是 父类的, interfaceType可能没有;
//obj 肯定有
//继续枚举 propertyInfo 下面的 [PropertyPush]
InitSubPropertyPush(this.obj.GetType().GetProperty(propertyInfo.Name), this.obj, null);
}
}
bool IsPropertyPush(PropertyInfo propertyInfo) {
if (propertyInfo.GetCustomAttribute<PropertyPushAttribute>() == null)
return false;//必须是[PropertyPush]
if (propertyInfo.CanWrite)
return false;//它只能是get,不能有set
void Sub_PropertyChanged(SubPropertyNode node, PropertyChangedEventArgs e)
{
//if (ignoreSet)//从服务器接收的数据,不用再推送给服务器
// return;
var type = node.Obj.GetType();
if (!typeof(INotifyPropertyChanged).IsAssignableFrom(propertyInfo.PropertyType))
return false;//必须是从INotifyPropertyChanged派生的
var propertyInfo = type.GetProperty(e.PropertyName);
if (propertyInfo == null)
return;//获取失败!!!
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);
if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() != null)
return;//这个不需要推送
((INotifyPropertyChanged)(propertyValue)).PropertyChanged += Sub_PropertyChanged;
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 subPropertyInfos = propertyInfo.PropertyType.GetProperties();
foreach (var subPropertyInfo in subPropertyInfos)
var rData = new Reflect_OBJ_INTERFACE.ReflectData
{
if (!IsPropertyPush(subPropertyInfo))
continue;//必须是[PropertyPush]
InitSubPropertyPush(subPropertyInfo, propertyValue, path);
}
name = COMMON.GetNodePath(node),
data = jObject
};
reponse_PushObjInfoEx(rData, false);
}
class AnyEvent
Reflect_OBJ_INTERFACE.ReflectData request_CALL_GetAllProperties()
{
public string eventName;
public Action<string> PushObjInfoEx;
public EventHandler eventHandler;
public AnyEvent()
var jObject = new JObject();
var type = obj.GetType();
foreach (var propertyName in properties)
{
eventHandler = new EventHandler(Obj_AnyEvent);
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));
}
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);
}
var rData = new Reflect_OBJ_INTERFACE.ReflectData
{
data = jObject
};
return rData;
}
private void Obj_PropertyChanged(object sender, PropertyChangedEventArgs e)
void request_CALL_SetProperty(Reflect_OBJ_INTERFACE.ReflectData rData)
{
//if (ignoreSet)//从服务器接收的数据,不用再推送给服务器
// return;
//ignoreSet = true;
if (interfaceType == null)
//sub property
var node = COMMON.FindNode(rootNode, rData.name);
if (node == null)
{
//异常
//客户端乱发过来
return;
}
if (!properties.Contains(e.PropertyName))
return;//这个不需要推送
string json = rData.data.ToString();
JsonConvert.PopulateObject(json, node.Obj);
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);
//ignoreSet = false;
}
private void Sub_PropertyChanged(object sender, PropertyChangedEventArgs e)
void request_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
{
//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<JsonIgnoreAttribute>() != 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;
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} 或者 参数名称不对,没法完全匹配");
}
string json = jObject_parent.ToString(Formatting.None);
CurrObjSys.PushObjInfoEx( this,
Reflect_OBJ_INTERFACE.PUSH_PropertyChanged,
Misc.Converter.StringToBytes(json));
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);
}
public override void CallFunction(IFConn from, uint srcid, uint magic, ushort funcid, byte[] infodata)
void asyncDelegate(object asyncContext, object retData)
{
switch (funcid)
var cc = (CC)asyncContext;
var rData = new Reflect_OBJ_INTERFACE.ReflectData()
{
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;
name = cc.methodName,
data = retData == null ? null : JToken.FromObject(retData)
};
case Reflect_OBJ_INTERFACE.CALL_MethodInvoke:
{
string json = Misc.Converter.BytesToString(infodata);
var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);
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} 或者 参数名称不对,没法完全匹配");
}
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)
{
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;
}
reponse_CALL_MethodInvoke(rData, cc);
}
MethodInfo GetMethodInfo(Type type, string name, IEnumerable<string> parameterNames)
MethodInfo GetMethodInfo(Type type, string name, IEnumerable<string> parameterNames)
{
var methodInfos = from mi in type.GetMethods() where mi.Name == name select mi;
if(methodInfos.Count()==0)
if (methodInfos.Count() == 0)
return null;
if (methodInfos.Count() == 1)
return methodInfos.First();
......@@ -369,7 +278,7 @@ namespace FObjBase.Reflect
//删除掉 asyncDelegate,asyncContext
names.Remove(Reflect_OBJ_INTERFACE.asyncDelegate);
names.Remove(Reflect_OBJ_INTERFACE.asyncContext);
var names_req = parameterNames;
if (names.Count() != names_req.Count())
......@@ -386,25 +295,85 @@ namespace FObjBase.Reflect
}
return null;
}
void asyncDelegate(object asyncContext, object retData)
public void Dispose()
{
var cc = (CC)asyncContext;
var rData = new Reflect_OBJ_INTERFACE.ReflectData()
if (typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
{
name = cc.methodName,
data = retData==null?null:JToken.FromObject(retData)
};
//继承了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,
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<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;
}
}
class CC
{
public IFConn from;
......@@ -413,4 +382,36 @@ namespace FObjBase.Reflect
public string methodName;
}
}
/// <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);
}
}
}
......@@ -12,27 +12,38 @@ namespace FObjBase.Reflect
{
public class Reflect_SeviceClient : FObjServiceClient
{
#region Core
/// <summary>
/// 忽略设置
/// </summary>
public bool ignoreSet;
/// <summary>
/// 代理对象 接口类型
/// </summary>
protected virtual Type InterfaceType { get; }
List<AnyEvent> anyEvents = new List<AnyEvent>();
List<AnyCall> anyCalls = new List<AnyCall>();
class AnyEvent
{
public string name;
public string triggerName;
public Type retType;
}
class AnyCall
class AnyCall
{
public string name;
public Type retType;
}
Dictionary<object,string> subProperties = new Dictionary<object, string>();
List<AnyEvent> anyEvents = new List<AnyEvent>();
List<AnyCall> anyCalls = new List<AnyCall>();
SubPropertyNode rootNode;
List<string> properties = new List<string>();
#endregion
public Reflect_SeviceClient(UInt32 id) : base(id) {
init();
}
......@@ -41,10 +52,19 @@ namespace FObjBase.Reflect
init();
}
void init() {
#region Core
void init()
{
rootNode = new SubPropertyNode
{
Obj = this,
InterfaceType = InterfaceType,
SubPropertyChanged = Sub_PropertyChanged
};
InitPropertyChanged();
InitPropertyPush();
COMMON.InitPropertyPush(rootNode);
InitEventPush();
InitCall();
}
......@@ -54,17 +74,9 @@ namespace FObjBase.Reflect
return;
//继承了INotifyPropertyChanged
this.PropertyChanged += Obj_PropertyChanged;
var interfaceTypes = new List<Type>();
interfaceTypes.Add(this.InterfaceType);
interfaceTypes.AddRange(this.InterfaceType.GetInterfaces());
this.PropertyChanged += rootNode.PropertyChanged;
var propertyInfos = new List<PropertyInfo>();
foreach (var ifaceType in interfaceTypes)
{
propertyInfos.AddRange(ifaceType.GetProperties());
}
var propertyInfos = COMMON.GetAllPropertyInfos(this.InterfaceType);//获取全部属性, 包括父类的属性
foreach (var propertyInfo in propertyInfos)
{
......@@ -78,59 +90,6 @@ namespace FObjBase.Reflect
}
}
void InitPropertyPush()
{
//处理[PropertyPush]
var interfaceTypes = new List<Type>();
interfaceTypes.Add(this.InterfaceType);
interfaceTypes.AddRange(this.InterfaceType.GetInterfaces());
var propertyInfos = new List<PropertyInfo>();
foreach (var ifaceType in interfaceTypes)
propertyInfos.AddRange(ifaceType.GetProperties());
foreach (var propertyInfo in propertyInfos)
{
if (!IsPropertyPush(propertyInfo))
continue;
InitSubPropertyPush(this.GetType().GetProperty(propertyInfo.Name), this, null);
}
}
bool IsPropertyPush(PropertyInfo propertyInfo)
{
if (propertyInfo.GetCustomAttribute<PropertyPushAttribute>() == 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);
}
}
void InitEventPush()
{
var interfaceTypes = new List<Type>();
......@@ -156,9 +115,10 @@ namespace FObjBase.Reflect
string triggerName;
if (string.IsNullOrEmpty(pushAttribute.TriggerName))
{
triggerName = "Trigger_" + eventInfo.Name;
triggerName = PushAttribute.DefaultTriggerNameHeader + eventInfo.Name;
}
else {
else
{
triggerName = pushAttribute.TriggerName;
}
var anyEvent = new AnyEvent()
......@@ -204,7 +164,8 @@ namespace FObjBase.Reflect
}
}
private void Obj_PropertyChanged(object sender, PropertyChangedEventArgs e)
private void Sub_PropertyChanged(SubPropertyNode node, PropertyChangedEventArgs e)
{
if (!IsConnected)
return;
......@@ -212,73 +173,134 @@ namespace FObjBase.Reflect
if (ignoreSet)//从服务器接收的数据,不用再推送给服务器
return;
if (InterfaceType == null)
return;
var type = node.Obj.GetType();
if (!properties.Contains(e.PropertyName))
return;//这个不需要推送
var propertyInfo = type.GetProperty(e.PropertyName);
if (propertyInfo == null)
return;//获取失败!!!
if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() != null)
return;//这个不需要推送
var v = GetType().GetProperty(e.PropertyName).GetValue(sender);
var v = propertyInfo.GetValue(node.Obj);
var jObject = new JObject();
if(v == null)
jObject.Add(e.PropertyName, null);
if (v == null)
jObject.Add(propertyInfo.Name, null);
else
jObject.Add(e.PropertyName, JToken.FromObject(v));
jObject.Add(propertyInfo.Name, JToken.FromObject(v));
var rData = new Reflect_OBJ_INTERFACE.ReflectData
{
name = COMMON.GetNodePath(node),
data = jObject
};
reponse_CALL_SetProperty(rData);
}
string json = jObject.ToString(Formatting.None);
CurrObjSys.CallFunctionEx(mConn, mServerID, ID,
Reflect_OBJ_INTERFACE.CALL_SetProperty,
Misc.Converter.StringToBytes(json));
public override void Dispose()
{
base.Dispose();
if (typeof(INotifyPropertyChanged).IsAssignableFrom(InterfaceType))
{
//继承了INotifyPropertyChanged
((INotifyPropertyChanged)(this)).PropertyChanged -= rootNode.PropertyChanged;
}
//释放subProperties
COMMON.NodeDispose(rootNode);
}
private void Sub_PropertyChanged(object sender, PropertyChangedEventArgs e)
protected void Call(string methodName, object parameters, AsyncCBHandler asyncDelegate, object asyncContext)
{
if (!IsConnected)
return;
var rData = new Reflect_OBJ_INTERFACE.ReflectData()
{
name = methodName,
data = parameters == null ? null : JObject.FromObject(parameters)
};
reponse_CALL_MethodInvoke(rData, asyncDelegate, asyncContext);
}
if (ignoreSet)//从服务器接收的数据,不用再推送给服务器
return;
if (!subProperties.ContainsKey(sender))
return;//异常, 不是子property
protected void Call(string methodName, object parameters)
{
Call(methodName, parameters, null, null);
}
var type = sender.GetType();
protected void Call(string methodName)
{
Call(methodName, null, null, null);
}
var propertyInfo = type.GetProperty(e.PropertyName);
if (propertyInfo == null)
return;//获取失败!!!
void request_PUSH_PropertyChanged(Reflect_OBJ_INTERFACE.ReflectData rData)
{
ignoreSet = true;
if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() != null)
return;//这个不需要推送
var node = COMMON.FindNode(rootNode, rData.name);
if (node == null)
{
//异常
//服务器乱发过来
return;
}
string path = subProperties[sender];
string[] parentNames = path.Split('.');
if (parentNames.Count() == 0)
string json = rData.data.ToString();
JsonConvert.PopulateObject(json, node.Obj);
ignoreSet = false;
}
void request_PUSH_Event(Reflect_OBJ_INTERFACE.ReflectData rData)
{
if (InterfaceType == null)
return;
var anyEvent = anyEvents.Find(ae => ae.name == rData.name);
if (anyEvent == null)
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++)
//触发事件!!!
var methodInfo = GetType().GetMethod(anyEvent.triggerName);
if (methodInfo == null)
{
throw new Exception($"客户端 {GetType()} 忘记写 {anyEvent.triggerName}");
}
var obj = rData.data.ToObject(anyEvent.retType);
//出错,就提示,肯定是客户端忘记写 "Trigger_XXXX"
methodInfo.Invoke(this, new object[] { obj });
}
void request_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, AsyncCBHandler asyncDelegate, object asyncContext)
{
var anyCall = anyCalls.Find(ac => ac.name == rData.name);
if (anyCall == null)
{
int idx = parentNames.Count() - 1 - i;
jObject_parent = new JObject();
jObject_parent.Add(parentNames[idx], jObject);
jObject = jObject_parent;
//异常!!!应该有[Call]注明返回的类型
throw new Exception($"{rData.name} 异常!!!应该有[Call]注明返回的类型");
}
string json = jObject_parent.ToString(Formatting.None);
var retData = rData.data.ToObject(anyCall.retType);
asyncDelegate.Invoke(asyncContext, retData);
}
#endregion
void reponse_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, AsyncCBHandler asyncDelegate, object asyncContext)
{
string json = JsonConvert.SerializeObject(rData);
CurrObjSys.CallFunctionEx(mConn, mServerID, ID,
Reflect_OBJ_INTERFACE.CALL_MethodInvoke,
Misc.Converter.StringToBytes(json),
asyncDelegate, asyncContext);
}
CurrObjSys.CallFunctionEx(mConn, mServerID, ID,
Reflect_OBJ_INTERFACE.CALL_SetProperty,
void reponse_CALL_SetProperty(Reflect_OBJ_INTERFACE.ReflectData rData)
{
string json = JsonConvert.SerializeObject(rData);
CurrObjSys.CallFunctionEx(mConn, mServerID, ID,
Reflect_OBJ_INTERFACE.CALL_SetProperty,
Misc.Converter.StringToBytes(json));
}
......@@ -301,8 +323,6 @@ namespace FObjBase.Reflect
}
}
public override void PushInfo(IFConn from, uint srcid, ushort infoid, byte[] infodata)
{
switch (infoid)
......@@ -310,33 +330,17 @@ namespace FObjBase.Reflect
case Reflect_OBJ_INTERFACE.PUSH_PropertyChanged:
{
string json = Misc.Converter.BytesToString(infodata);
ignoreSet = true;
JsonConvert.PopulateObject(json, this);
ignoreSet = false;
var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);
request_PUSH_PropertyChanged(rData);
}
break;
case Reflect_OBJ_INTERFACE.PUSH_Event:
{
if (InterfaceType == null)
return;
string json = Misc.Converter.BytesToString(infodata);
var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);
var anyEvent = anyEvents.Find(ae => ae.name == rData.name);
if (anyEvent == null)
return;//异常!!!
//触发事件!!!
var methodInfo = GetType().GetMethod(anyEvent.triggerName);
if (methodInfo == null)
{
throw new Exception($"客户端 {GetType()} 忘记写 {anyEvent.triggerName}");
}
var obj = rData.data.ToObject(anyEvent.retType);
//出错,就提示,肯定是客户端忘记写 "Trigger_XXXX"
methodInfo.Invoke(this, new object[] { obj });
request_PUSH_Event(rData);
}
break;
}
......@@ -350,9 +354,9 @@ namespace FObjBase.Reflect
case Reflect_OBJ_INTERFACE.CALL_GetAllProperties:
{
string json = Misc.Converter.BytesToString(retdata);
ignoreSet = true;
JsonConvert.PopulateObject(json, this);
ignoreSet = false;
var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);
request_PUSH_PropertyChanged(rData);
}
break;
case Reflect_OBJ_INTERFACE.CALL_MethodInvoke:
......@@ -361,43 +365,14 @@ namespace FObjBase.Reflect
return;
string json = Misc.Converter.BytesToString(retdata);
var reponse = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);
var anyCall = anyCalls.Find(ac => ac.name == reponse.name);
if (anyCall == null)
{
//异常!!!应该有[Call]注明返回的类型
throw new Exception($"{reponse.name} 异常!!!应该有[Call]注明返回的类型");
}
var retData = reponse.data.ToObject(anyCall.retType);
((AsyncCBHandler)asyncDelegate).Invoke(asyncContext, retData);
var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);
request_CALL_MethodInvoke(rData, (AsyncCBHandler)asyncDelegate, asyncContext);
}
break;
}
}
protected void Call(string methodName, object parameters, AsyncCBHandler asyncDelegate, object asyncContext)
{
var rData = new Reflect_OBJ_INTERFACE.ReflectData()
{
name = methodName,
data = parameters==null?null:JObject.FromObject(parameters)
};
string json = JsonConvert.SerializeObject(rData);
CurrObjSys.CallFunctionEx(mConn, mServerID, ID,
Reflect_OBJ_INTERFACE.CALL_MethodInvoke,
Misc.Converter.StringToBytes(json),
asyncDelegate, asyncContext);
}
protected void Call(string methodName, object parameters) {
Call(methodName, parameters, null, null);
}
protected void Call(string methodName)
{
Call(methodName, null, null, null);
}
#endregion
}
}
......@@ -867,9 +867,9 @@ namespace FObjBase
obj.ConnectNotify(cc);
}
}
catch
catch(Exception e)
{
throw e;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment