2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-05-06 19:42:58 +00:00

GetHierarchy

This commit is contained in:
Esiur Project 2022-08-20 01:57:18 +03:00
parent ebcf8525fa
commit acc2a546cf
9 changed files with 280 additions and 153 deletions

View File

@ -6,7 +6,7 @@
<Copyright>Ahmed Kh. Zamil</Copyright> <Copyright>Ahmed Kh. Zamil</Copyright>
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl> <PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>2.2.8</Version> <Version>2.2.9</Version>
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl> <RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
<Authors>Ahmed Kh. Zamil</Authors> <Authors>Ahmed Kh. Zamil</Authors>
<AssemblyVersion></AssemblyVersion> <AssemblyVersion></AssemblyVersion>

View File

@ -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;
}
} }

View File

@ -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<AnnotationAttribute>(true); var annotationAttr = ci.GetCustomAttribute<AnnotationAttribute>(true);
var nullableAttr = ci.GetCustomAttribute<NullableAttribute>(true); var nullableAttr = ci.GetCustomAttribute<NullableAttribute>(true);
@ -84,7 +84,7 @@ public class ConstantTemplate : MemberTemplate
if (typeTemplate?.Type == TemplateType.Enum) if (typeTemplate?.Type == TemplateType.Enum)
value = Convert.ChangeType(value, ci.FieldType.GetEnumUnderlyingType()); 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; ct.FieldInfo = ci;
return ct; return ct;

View File

@ -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<AnnotationAttribute>();
if (annotationAttr != null)
rt = annotationAttr.Annotation;
md = md.Child;
}
return rt;
}
}

View File

@ -426,158 +426,71 @@ public class TypeTemplate
PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); //PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance); //EventInfo[] eventsInfo = type.GetEvents(BindingFlags.Public | BindingFlags.Instance);
MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); //MethodInfo[] methodsInfo = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
FieldInfo[] constantsInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static); //FieldInfo[] constantsInfo = type.GetFields(BindingFlags.Public | BindingFlags.Static);
bool classIsPublic = type.IsEnum || (type.GetCustomAttribute<PublicAttribute>() != null); //bool classIsPublic = type.IsEnum || (type.GetCustomAttribute<PublicAttribute>() != null);
var hierarchy = GetHierarchy(type);
if (hierarchy.ContainsKey(MemberTypes.Field))
var addAttribute = (PropertyInfo pi, AttributeAttribute attributeAttr) =>
{ {
var an = attributeAttr.Name ?? pi.Name; foreach (var cd in hierarchy[MemberTypes.Field])
var at = new AttributeTemplate(this, 0, an, pi.DeclaringType != type);
at.PropertyInfo = pi;
attributes.Add(at);
};
if (classIsPublic)
{ {
constants.Add(ConstantTemplate.MakeConstantTemplate
foreach (var ci in constantsInfo) (type, (FieldInfo)cd.GetMemberInfo(), cd.Index, cd.Name, this));
{ }
var privateAttr = ci.GetCustomAttribute<PrivateAttribute>(true);
if (privateAttr != null)
continue;
var publicAttr = ci.GetCustomAttribute<PublicAttribute>(true);
var ct = MakeConstantTemplate(type, ci, publicAttr, (byte)constants.Count, this);
constants.Add(ct);
} }
if (hierarchy.ContainsKey(MemberTypes.Property))
foreach (var pi in propsInfo)
{ {
var privateAttr = pi.GetCustomAttribute<PrivateAttribute>(true); foreach (var pd in hierarchy[MemberTypes.Property])
if (privateAttr == null)
{ {
var publicAttr = pi.GetCustomAttribute<PublicAttribute>(true); properties.Add(PropertyTemplate.MakePropertyTemplate
var pt = PropertyTemplate.MakePropertyTemplate(type, pi, (byte)properties.Count, publicAttr?.Name, this); (type, (PropertyInfo)pd.GetMemberInfo(), pd.Index, pd.Name, this));
properties.Add(pt);
}
else
{
var attributeAttr = pi.GetCustomAttribute<AttributeAttribute>(true);
if (attributeAttr != null)
{
addAttribute(pi, attributeAttr);
}
} }
} }
if (templateType == TemplateType.Resource if (templateType == TemplateType.Resource
|| templateType == TemplateType.Wrapper) || templateType == TemplateType.Wrapper)
{ {
if (hierarchy.ContainsKey(MemberTypes.Method))
foreach (var ei in eventsInfo)
{ {
var privateAttr = ei.GetCustomAttribute<PrivateAttribute>(true); foreach (var fd in hierarchy[MemberTypes.Method])
if (privateAttr != null)
continue;
var publicAttr = ei.GetCustomAttribute<PublicAttribute>(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<PrivateAttribute>(true); functions.Add(FunctionTemplate.MakeFunctionTemplate
if (privateAttr != null) (type, (MethodInfo)fd.GetMemberInfo(), fd.Index, fd.Name, this));
continue; }
var publicAttr = mi.GetCustomAttribute<PublicAttribute>(true);
var ft = FunctionTemplate.MakeFunctionTemplate(type, mi, (byte)functions.Count, publicAttr?.Name, this);
functions.Add(ft);
//addFunction(mi, publicAttr);
} }
} if (hierarchy.ContainsKey(MemberTypes.Event))
}
else
{ {
foreach (var ci in constantsInfo) foreach (var ed in hierarchy[MemberTypes.Event])
{ {
var publicAttr = ci.GetCustomAttribute<PublicAttribute>(true); events.Add(EventTemplate.MakeEventTemplate
(type, (EventInfo)ed.GetMemberInfo(), ed.Index, ed.Name, this));
if (publicAttr == null) }
continue;
var ct = MakeConstantTemplate(type, ci, publicAttr, (byte)constants.Count, this);
constants.Add(ct);
} }
}
foreach (var pi in propsInfo) // add attributes
var attrs = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.GetCustomAttribute<AttributeAttribute>() != null);
foreach (var attr in attrs)
{ {
var publicAttr = pi.GetCustomAttribute<PublicAttribute>(true); var attrAttr = attr.GetCustomAttribute<AttributeAttribute>();
if (publicAttr != null) attributes.Add(AttributeTemplate
{ .MakeAttributeTemplate(type, attr, 0, attrAttr?.Name ?? attr.Name, this));
var pt = PropertyTemplate.MakePropertyTemplate(type, pi, (byte)properties.Count, publicAttr?.Name, this);
properties.Add(pt);
}
else
{
var attributeAttr = pi.GetCustomAttribute<AttributeAttribute>(true);
if (attributeAttr != null)
{
addAttribute(pi, attributeAttr);
}
}
} }
if (templateType == TemplateType.Resource // append signals)
|| templateType == TemplateType.Wrapper)
{
foreach (var ei in eventsInfo)
{
var publicAttr = ei.GetCustomAttribute<PublicAttribute>(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<PublicAttribute>(true);
if (publicAttr == null)
continue;
var ft = FunctionTemplate.MakeFunctionTemplate(type, mi, (byte)functions.Count, publicAttr?.Name, this);
functions.Add(ft);
//addFunction(mi, publicAttr);
}
}
}
// append signals
for (var i = 0; i < events.Count; i++) for (var i = 0; i < events.Count; i++)
members.Add(events[i]); members.Add(events[i]);
// append slots // append slots
@ -645,22 +558,146 @@ public class TypeTemplate
{ {
var parent = type.BaseType; var parent = type.BaseType;
while (parent != null)
{
if (parent == typeof(Resource) if (parent == typeof(Resource)
|| parent == typeof(Record) || parent == typeof(Record)
|| parent == typeof(EntryPoint)) || parent == typeof(EntryPoint))
return false; return false;
while (parent != null)
{
if (parent.GetInterfaces().Contains(typeof(IResource)) if (parent.GetInterfaces().Contains(typeof(IResource))
|| parent.GetInterfaces().Contains(typeof(IRecord))) || parent.GetInterfaces().Contains(typeof(IRecord)))
return true; return true;
parent = parent.BaseType; parent = parent.BaseType;
} }
return false; return false;
} }
public static Dictionary<MemberTypes, List<MemberData>> GetHierarchy(Type type)
{
var members = new List<MemberData>();
var order = 0;
while (type != null)
{
var classIsPublic = type.IsEnum || (type.GetCustomAttribute<PublicAttribute>() != 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<PrivateAttribute>() == null)
.Where(x => !(x is MethodInfo m && m.IsSpecialName))
.Select(x => new MemberData()
{
Name = x.GetCustomAttribute<PublicAttribute>()?.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<PublicAttribute>() != null)
.Where(x => !(x is MethodInfo m && m.IsSpecialName))
.Select(x => new MemberData
{
Name = x.GetCustomAttribute<PublicAttribute>()?.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) public static TypeTemplate Parse(byte[] data)
{ {
return Parse(data, 0, (uint)data.Length); return Parse(data, 0, (uint)data.Length);

View File

@ -11,5 +11,6 @@ namespace Test
public class MyChildRecord : MyRecord public class MyChildRecord : MyRecord
{ {
public string ChildName { get; set; } public string ChildName { get; set; }
} }
} }

View File

@ -11,6 +11,10 @@ namespace Test
public partial class MyChildResource : MyResource public partial class MyChildResource : MyResource
{ {
[Public] string childName; [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";
} }
} }

View File

@ -13,5 +13,11 @@ namespace Test
{ {
[Public][Annotation("Comment")] string description; [Public][Annotation("Comment")] string description;
[Public] int categoryId; [Public] int categoryId;
[Public] public string Hello() => "Hi";
[Public] public string HelloParent() => "Hi from Parent";
} }
} }

View File

@ -42,6 +42,7 @@ using System.Runtime.CompilerServices;
using Esiur.Proxy; using Esiur.Proxy;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection;
namespace Test namespace Test
{ {
@ -54,6 +55,10 @@ namespace Test
static async Task Main(string[] args) 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. // Create stores to keep objects.
var system = await Warehouse.Put("sys", new MemoryStore()); var system = await Warehouse.Put("sys", new MemoryStore());
var server = await Warehouse.Put("sys/server", new DistributedServer()); var server = await Warehouse.Put("sys/server", new DistributedServer());
@ -222,6 +227,28 @@ namespace Test
return value.ToString(); return value.ToString();
} }
public static IEnumerable<PropertyInfo> GetOrderedProperties(Type type)
{
Dictionary<Type, int> lookup = new Dictionary<Type, int>();
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]);
}
} }