diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj
index e094037..4519c97 100644
--- a/Esiur/Esiur.csproj
+++ b/Esiur/Esiur.csproj
@@ -6,7 +6,7 @@
Ahmed Kh. Zamil
http://www.esiur.com
true
- 2.2.8
+ 2.2.9
https://github.com/esiur/esiur-dotnet
Ahmed Kh. Zamil
diff --git a/Esiur/Resource/Template/AttributeTemplate.cs b/Esiur/Resource/Template/AttributeTemplate.cs
index d4d8ac5..8bdc473 100644
--- a/Esiur/Resource/Template/AttributeTemplate.cs
+++ b/Esiur/Resource/Template/AttributeTemplate.cs
@@ -21,4 +21,11 @@ public class AttributeTemplate : MemberTemplate
{
}
+
+ public static AttributeTemplate MakeAttributeTemplate(Type type, PropertyInfo pi, byte index = 0, string customName = null, TypeTemplate typeTemplate = null)
+ {
+ var at = new AttributeTemplate(typeTemplate, index, customName, pi.DeclaringType != type);
+ at.PropertyInfo = pi;
+ return at;
+ }
}
diff --git a/Esiur/Resource/Template/ConstantTemplate.cs b/Esiur/Resource/Template/ConstantTemplate.cs
index 3844573..8395277 100644
--- a/Esiur/Resource/Template/ConstantTemplate.cs
+++ b/Esiur/Resource/Template/ConstantTemplate.cs
@@ -69,7 +69,7 @@ public class ConstantTemplate : MemberTemplate
}
- public static ConstantTemplate MakeConstantTemplate(Type type, FieldInfo ci, PublicAttribute publicAttr, byte index = 0, TypeTemplate typeTemplate = null)
+ public static ConstantTemplate MakeConstantTemplate(Type type, FieldInfo ci, byte index = 0, string customName = null, TypeTemplate typeTemplate = null)
{
var annotationAttr = ci.GetCustomAttribute(true);
var nullableAttr = ci.GetCustomAttribute(true);
@@ -84,7 +84,7 @@ public class ConstantTemplate : MemberTemplate
if (typeTemplate?.Type == TemplateType.Enum)
value = Convert.ChangeType(value, ci.FieldType.GetEnumUnderlyingType());
- var ct = new ConstantTemplate(typeTemplate, index, publicAttr?.Name ?? ci.Name, ci.DeclaringType != type, valueType, value, annotationAttr?.Annotation);
+ var ct = new ConstantTemplate(typeTemplate, index, customName ?? ci.Name, ci.DeclaringType != type, valueType, value, annotationAttr?.Annotation);
ct.FieldInfo = ci;
return ct;
diff --git a/Esiur/Resource/Template/MemberData.cs b/Esiur/Resource/Template/MemberData.cs
new file mode 100644
index 0000000..a2f4107
--- /dev/null
+++ b/Esiur/Resource/Template/MemberData.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace Esiur.Resource.Template;
+
+public class MemberData
+{
+ public MemberInfo Info;
+ public string Name;
+ public int Order;
+ //public bool Inherited;
+ public MemberData? Parent;
+ public MemberData? Child;
+ public byte Index;
+
+ public MemberInfo GetMemberInfo()
+ {
+ var rt = Info;
+ var md = Child;
+ while (md != null)
+ {
+ rt = Info;
+ md = md.Child;
+ }
+ return rt;
+ }
+
+ public string? GetAnnotation()
+ {
+ string rt = null;
+ var md = this;
+ while (md != null)
+ {
+ var annotationAttr = md.Info.GetCustomAttribute();
+ if (annotationAttr != null)
+ rt = annotationAttr.Annotation;
+ md = md.Child;
+ }
+
+ return rt;
+ }
+}
+
diff --git a/Esiur/Resource/Template/TypeTemplate.cs b/Esiur/Resource/Template/TypeTemplate.cs
index c96b3e0..7ab6dec 100644
--- a/Esiur/Resource/Template/TypeTemplate.cs
+++ b/Esiur/Resource/Template/TypeTemplate.cs
@@ -369,7 +369,7 @@ public class TypeTemplate
}
-
+
public static ConstantTemplate MakeConstantTemplate(Type type, FieldInfo ci, PublicAttribute publicAttr, byte index = 0, TypeTemplate typeTemplate = null)
{
@@ -392,7 +392,7 @@ public class TypeTemplate
}
-
+
public TypeTemplate(Type type, bool addToWarehouse = false)
{
if (Codec.InheritsClass(type, typeof(DistributedResource)))
@@ -426,158 +426,71 @@ public class TypeTemplate
- PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
- EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance);
- MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
- FieldInfo[] constantsInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static);
+ //PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ //EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance);
+ //MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
+ //FieldInfo[] constantsInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static);
- bool classIsPublic = type.IsEnum || (type.GetCustomAttribute() != null);
+ //bool classIsPublic = type.IsEnum || (type.GetCustomAttribute() != null);
-
-
-
- var addAttribute = (PropertyInfo pi, AttributeAttribute attributeAttr) =>
+ var hierarchy = GetHierarchy(type);
+
+ if (hierarchy.ContainsKey(MemberTypes.Field))
{
- var an = attributeAttr.Name ?? pi.Name;
- var at = new AttributeTemplate(this, 0, an, pi.DeclaringType != type);
- at.PropertyInfo = pi;
- attributes.Add(at);
- };
-
-
-
-
-
- if (classIsPublic)
- {
-
- foreach (var ci in constantsInfo)
+ foreach (var cd in hierarchy[MemberTypes.Field])
{
- var privateAttr = ci.GetCustomAttribute(true);
-
- if (privateAttr != null)
- continue;
-
- var publicAttr = ci.GetCustomAttribute(true);
-
- var ct = MakeConstantTemplate(type, ci, publicAttr, (byte)constants.Count, this);
- constants.Add(ct);
- }
-
-
- foreach (var pi in propsInfo)
- {
- var privateAttr = pi.GetCustomAttribute(true);
-
- if (privateAttr == null)
- {
- var publicAttr = pi.GetCustomAttribute(true);
- var pt = PropertyTemplate.MakePropertyTemplate(type, pi, (byte)properties.Count, publicAttr?.Name, this);
- properties.Add(pt);
- }
- else
- {
- var attributeAttr = pi.GetCustomAttribute(true);
- if (attributeAttr != null)
- {
- addAttribute(pi, attributeAttr);
- }
- }
- }
-
- if (templateType == TemplateType.Resource
- || templateType == TemplateType.Wrapper)
- {
-
- foreach (var ei in eventsInfo)
- {
- var privateAttr = ei.GetCustomAttribute(true);
- if (privateAttr != null)
- continue;
-
- var publicAttr = ei.GetCustomAttribute(true);
- var et = EventTemplate.MakeEventTemplate(type, ei, (byte)events.Count, publicAttr?.Name, this);
- events.Add(et);
- }
-
- foreach (MethodInfo mi in methodsInfo)
- {
- var privateAttr = mi.GetCustomAttribute(true);
- if (privateAttr != null)
- continue;
-
- var publicAttr = mi.GetCustomAttribute(true);
- var ft = FunctionTemplate.MakeFunctionTemplate(type, mi, (byte)functions.Count, publicAttr?.Name, this);
- functions.Add(ft);
- //addFunction(mi, publicAttr);
- }
-
- }
- }
- else
- {
- foreach (var ci in constantsInfo)
- {
- var publicAttr = ci.GetCustomAttribute(true);
-
- if (publicAttr == null)
- continue;
-
- var ct = MakeConstantTemplate(type, ci, publicAttr, (byte)constants.Count, this);
- constants.Add(ct);
- }
-
-
- foreach (var pi in propsInfo)
- {
- var publicAttr = pi.GetCustomAttribute(true);
-
- if (publicAttr != null)
- {
- var pt = PropertyTemplate.MakePropertyTemplate(type, pi, (byte)properties.Count, publicAttr?.Name, this);
- properties.Add(pt);
- }
- else
- {
- var attributeAttr = pi.GetCustomAttribute(true);
- if (attributeAttr != null)
- {
- addAttribute(pi, attributeAttr);
- }
- }
- }
-
- if (templateType == TemplateType.Resource
- || templateType == TemplateType.Wrapper)
- {
-
- foreach (var ei in eventsInfo)
- {
- var publicAttr = ei.GetCustomAttribute(true);
-
- if (publicAttr == null)
- continue;
-
- var et = EventTemplate.MakeEventTemplate(type, ei, (byte)events.Count, publicAttr?.Name, this);
- events.Add(et);
- }
-
- foreach (MethodInfo mi in methodsInfo)
- {
- var publicAttr = mi.GetCustomAttribute(true);
- if (publicAttr == null)
- continue;
-
- var ft = FunctionTemplate.MakeFunctionTemplate(type, mi, (byte)functions.Count, publicAttr?.Name, this);
- functions.Add(ft);
- //addFunction(mi, publicAttr);
- }
+ constants.Add(ConstantTemplate.MakeConstantTemplate
+ (type, (FieldInfo)cd.GetMemberInfo(), cd.Index, cd.Name, this));
}
}
- // append signals
+ if (hierarchy.ContainsKey(MemberTypes.Property))
+ {
+ foreach (var pd in hierarchy[MemberTypes.Property])
+ {
+ properties.Add(PropertyTemplate.MakePropertyTemplate
+ (type, (PropertyInfo)pd.GetMemberInfo(), pd.Index, pd.Name, this));
+ }
+ }
+
+ if (templateType == TemplateType.Resource
+ || templateType == TemplateType.Wrapper)
+ {
+ if (hierarchy.ContainsKey(MemberTypes.Method))
+ {
+ foreach (var fd in hierarchy[MemberTypes.Method])
+ {
+ functions.Add(FunctionTemplate.MakeFunctionTemplate
+ (type, (MethodInfo)fd.GetMemberInfo(), fd.Index, fd.Name, this));
+ }
+ }
+
+ if (hierarchy.ContainsKey(MemberTypes.Event))
+ {
+ foreach (var ed in hierarchy[MemberTypes.Event])
+ {
+ events.Add(EventTemplate.MakeEventTemplate
+ (type, (EventInfo)ed.GetMemberInfo(), ed.Index, ed.Name, this));
+ }
+ }
+
+ }
+
+ // add attributes
+ var attrs = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
+ .Where(x => x.GetCustomAttribute() != null);
+
+ foreach (var attr in attrs)
+ {
+ var attrAttr = attr.GetCustomAttribute();
+
+ attributes.Add(AttributeTemplate
+ .MakeAttributeTemplate(type, attr, 0, attrAttr?.Name ?? attr.Name, this));
+ }
+
+ // append signals)
for (var i = 0; i < events.Count; i++)
members.Add(events[i]);
// append slots
@@ -645,22 +558,146 @@ public class TypeTemplate
{
var parent = type.BaseType;
- if (parent == typeof(Resource)
- || parent == typeof(Record)
- || parent == typeof(EntryPoint))
- return false;
while (parent != null)
{
+ if (parent == typeof(Resource)
+ || parent == typeof(Record)
+ || parent == typeof(EntryPoint))
+ return false;
+
if (parent.GetInterfaces().Contains(typeof(IResource))
|| parent.GetInterfaces().Contains(typeof(IRecord)))
return true;
+
parent = parent.BaseType;
}
return false;
}
+
+
+ public static Dictionary> GetHierarchy(Type type)
+ {
+ var members = new List();
+
+ var order = 0;
+
+ while (type != null)
+ {
+ var classIsPublic = type.IsEnum || (type.GetCustomAttribute() != null);
+
+ if (classIsPublic)
+ {
+ var mis = type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
+ .Where(x => x.MemberType == MemberTypes.Property || x.MemberType == MemberTypes.Field
+ || x.MemberType == MemberTypes.Event || x.MemberType == MemberTypes.Method)
+ .Where(x => !(x is FieldInfo c && !c.IsStatic))
+ .Where(x => x.GetCustomAttribute() == null)
+ .Where(x => !(x is MethodInfo m && m.IsSpecialName))
+ .Select(x => new MemberData()
+ {
+ Name = x.GetCustomAttribute()?.Name ?? x.Name,
+ Info = x,
+ Order = order
+ })
+ .OrderBy(x => x.Name);
+
+ members.AddRange(mis.ToArray());
+
+ }
+ else
+ {
+ var mis = type.GetMembers(BindingFlags.Public | BindingFlags.Instance
+ | BindingFlags.DeclaredOnly | BindingFlags.Static)
+ .Where(x => x.MemberType == MemberTypes.Property || x.MemberType == MemberTypes.Field
+ || x.MemberType == MemberTypes.Event || x.MemberType == MemberTypes.Method)
+ .Where(x => !(x is FieldInfo c && !c.IsStatic))
+ .Where(x => x.GetCustomAttribute() != null)
+ .Where(x => !(x is MethodInfo m && m.IsSpecialName))
+ .Select(x => new MemberData
+ {
+ Name = x.GetCustomAttribute()?.Name ?? x.Name,
+ Info = x,
+ Order = order
+ })
+ .OrderBy(x => x.Name);
+
+ members.AddRange(mis.ToArray());
+
+ }
+
+ type = type.BaseType;
+
+ if (type == typeof(Resource)
+ || type == typeof(Record)
+ || type == typeof(EntryPoint))
+ break;
+
+ if (type.GetInterfaces().Contains(typeof(IResource))
+ || type.GetInterfaces().Contains(typeof(IRecord)))
+ {
+ order++;
+ continue;
+ }
+
+ break;
+ }
+
+ // round 2: check for duplicates
+ for (var i = 0; i < members.Count; i++)
+ {
+ var mi = members[i];
+ for (var j = i + 1; j < members.Count; j++)
+ {
+ var pi = members[j];
+ if (pi.Info.MemberType != mi.Info.MemberType)
+ continue;
+
+ //if (ci.Info.Name == mi.Info.Name && ci.Order == mi.Order)
+ // throw new Exception($"Method overload is not supported. Method '{ci.Info.Name}'.");
+
+ if (pi.Name == mi.Name)
+ {
+ if (pi.Order == mi.Order)
+ throw new Exception($"Duplicate definitions for members public name '{mi.Info.DeclaringType.Name}:{mi.Info.Name}' and '{pi.Info.DeclaringType.Name}:{pi.Info.Name}'.");
+ else
+ {
+ // @TODO: check for return type and parameters they must match
+ if (pi.Info.Name != mi.Info.Name)
+ throw new Exception($"Duplicate definitions for members public name '{mi.Info.DeclaringType.Name}:{mi.Info.Name}' and '{pi.Info.DeclaringType.Name}:{pi.Info.Name}'.");
+ }
+
+ mi.Parent = pi;
+ pi.Child = mi;
+ }
+
+ }
+ }
+
+
+ // assign indexies
+ var groups = members.Where(x => x.Parent == null)
+ .OrderBy(x => x.Name).OrderByDescending(x => x.Order)
+ .GroupBy(x => x.Info.MemberType);
+
+ foreach (var group in groups)
+ {
+ byte index = 0;
+ foreach (var mi in group)
+ {
+ //if (mi.Parent == null)
+ mi.Index = index++;
+ }
+ }
+
+ var rt = groups.ToDictionary(g => g.Key, g => g.ToList());
+
+ return rt;
+ }
+
+
public static TypeTemplate Parse(byte[] data)
{
return Parse(data, 0, (uint)data.Length);
diff --git a/Test/MyChildRecord.cs b/Test/MyChildRecord.cs
index 484174f..124ce53 100644
--- a/Test/MyChildRecord.cs
+++ b/Test/MyChildRecord.cs
@@ -11,5 +11,6 @@ namespace Test
public class MyChildRecord : MyRecord
{
public string ChildName { get; set; }
+
}
}
diff --git a/Test/MyChildResource.cs b/Test/MyChildResource.cs
index 2a5c122..a32349d 100644
--- a/Test/MyChildResource.cs
+++ b/Test/MyChildResource.cs
@@ -11,6 +11,10 @@ namespace Test
public partial class MyChildResource : MyResource
{
[Public] string childName;
- [Public] public int ChildMethod(string childName) => 111;
+ [Public("Hell2o")] public int ChildMethod(string childName) => 111;
+ [Public] public new string Hello() => "Hi from Child";
+
+ [Public] public string HelloChild() => "Hi from Child";
+
}
}
diff --git a/Test/MyResource.cs b/Test/MyResource.cs
index 66a3423..237cb77 100644
--- a/Test/MyResource.cs
+++ b/Test/MyResource.cs
@@ -13,5 +13,11 @@ namespace Test
{
[Public][Annotation("Comment")] string description;
[Public] int categoryId;
+
+
+ [Public] public string Hello() => "Hi";
+
+ [Public] public string HelloParent() => "Hi from Parent";
+
}
}
diff --git a/Test/Program.cs b/Test/Program.cs
index 6f38399..ef616e1 100644
--- a/Test/Program.cs
+++ b/Test/Program.cs
@@ -42,6 +42,7 @@ using System.Runtime.CompilerServices;
using Esiur.Proxy;
using System.Text.RegularExpressions;
using System.Collections.Generic;
+using System.Reflection;
namespace Test
{
@@ -54,6 +55,10 @@ namespace Test
static async Task Main(string[] args)
{
+ var ppp = GetOrderedProperties(typeof(MyChildResource)).ToArray();
+ var childMethods = typeof(MyChildResource).GetMembers( BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
+ var parentMethods = typeof(MyResource).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
+
// Create stores to keep objects.
var system = await Warehouse.Put("sys", new MemoryStore());
var server = await Warehouse.Put("sys/server", new DistributedServer());
@@ -222,6 +227,28 @@ namespace Test
return value.ToString();
}
+
+
+
+
+ public static IEnumerable GetOrderedProperties(Type type)
+ {
+ Dictionary lookup = new Dictionary();
+
+ int count = 0;
+ lookup[type] = count++;
+ Type parent = type.BaseType;
+ while (parent != null)
+ {
+ lookup[parent] = count;
+ count++;
+ parent = parent.BaseType;
+ }
+
+ return type.GetProperties()
+ .OrderByDescending(prop => lookup[prop.DeclaringType]);
+ }
+
}