mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-05-06 11:32:59 +00:00
GetHierarchy
This commit is contained in:
parent
ebcf8525fa
commit
acc2a546cf
@ -6,7 +6,7 @@
|
||||
<Copyright>Ahmed Kh. Zamil</Copyright>
|
||||
<PackageProjectUrl>http://www.esiur.com</PackageProjectUrl>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>2.2.8</Version>
|
||||
<Version>2.2.9</Version>
|
||||
<RepositoryUrl>https://github.com/esiur/esiur-dotnet</RepositoryUrl>
|
||||
<Authors>Ahmed Kh. Zamil</Authors>
|
||||
<AssemblyVersion></AssemblyVersion>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 nullableAttr = ci.GetCustomAttribute<NullableAttribute>(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;
|
||||
|
45
Esiur/Resource/Template/MemberData.cs
Normal file
45
Esiur/Resource/Template/MemberData.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -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<PublicAttribute>() != null);
|
||||
//bool classIsPublic = type.IsEnum || (type.GetCustomAttribute<PublicAttribute>() != 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<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);
|
||||
}
|
||||
|
||||
|
||||
foreach (var pi in propsInfo)
|
||||
{
|
||||
var privateAttr = pi.GetCustomAttribute<PrivateAttribute>(true);
|
||||
|
||||
if (privateAttr == null)
|
||||
{
|
||||
var publicAttr = pi.GetCustomAttribute<PublicAttribute>(true);
|
||||
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
|
||||
|| templateType == TemplateType.Wrapper)
|
||||
{
|
||||
|
||||
foreach (var ei in eventsInfo)
|
||||
{
|
||||
var privateAttr = ei.GetCustomAttribute<PrivateAttribute>(true);
|
||||
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);
|
||||
if (privateAttr != null)
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var ci in constantsInfo)
|
||||
{
|
||||
var publicAttr = ci.GetCustomAttribute<PublicAttribute>(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<PublicAttribute>(true);
|
||||
|
||||
if (publicAttr != null)
|
||||
{
|
||||
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
|
||||
|| 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);
|
||||
}
|
||||
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<AttributeAttribute>() != null);
|
||||
|
||||
foreach (var attr in attrs)
|
||||
{
|
||||
var attrAttr = attr.GetCustomAttribute<AttributeAttribute>();
|
||||
|
||||
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<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)
|
||||
{
|
||||
return Parse(data, 0, (uint)data.Length);
|
||||
|
@ -11,5 +11,6 @@ namespace Test
|
||||
public class MyChildRecord : MyRecord
|
||||
{
|
||||
public string ChildName { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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<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]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user