Skip to content

Commit

Permalink
Integrate FrozenDictionary
Browse files Browse the repository at this point in the history
  • Loading branch information
JLChnToZ committed Jul 27, 2024
1 parent 23d6a36 commit e95ae29
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<defaultNamespace>JLChnToZ.CommonUtils.Dynamic</defaultNamespace>
</PropertyGroup>

</Project>
92 changes: 61 additions & 31 deletions JLChnToZ.CommonUtils.Dynamic/TypeInfo.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
using System;
using System.Collections.Generic;
#if NET8_0_OR_GREATER
using System.Collections.Frozen;
#endif
using System.Dynamic;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace JLChnToZ.CommonUtils.Dynamic {
using static Utilites;

/// <summary>Internal struct that holds type members information.</summary>
public readonly struct TypeInfo {
public readonly struct TypeInfo : IEquatable<TypeInfo> {
static readonly Dictionary<Type, TypeInfo> cache = new Dictionary<Type, TypeInfo>();
internal readonly Type type;
readonly ConstructorInfo[] constructors;
internal readonly PropertyInfo[] indexers;
readonly Dictionary<string, MethodInfo[]> methods;
readonly Dictionary<string, PropertyInfo> properties;
readonly Dictionary<string, FieldInfo> fields;
readonly Dictionary<string, EventInfo> events;
readonly Dictionary<Type, MethodInfo> castInOperators;
readonly Dictionary<Type, MethodInfo> castOutOperators;
readonly Dictionary<string, Type> subTypes;
readonly IReadOnlyDictionary<(string, MemberType), MemberInfo> members;
readonly IReadOnlyDictionary<string, MethodInfo[]> methods;
readonly IReadOnlyDictionary<(Type, MemberType), MethodInfo> castOperators;

public static TypeInfo Get(Type type) {
if (!cache.TryGetValue(type, out var typeInfo))
Expand All @@ -29,13 +29,9 @@ public static TypeInfo Get(Type type) {
TypeInfo(Type type) {
if (type == null) throw new ArgumentNullException(nameof(type));
this.type = type;
methods = new Dictionary<string, MethodInfo[]>();
properties = new Dictionary<string, PropertyInfo>();
fields = new Dictionary<string, FieldInfo>();
events = new Dictionary<string, EventInfo>();
castInOperators = new Dictionary<Type, MethodInfo>();
castOutOperators = new Dictionary<Type, MethodInfo>();
subTypes = new Dictionary<string, Type>();
var tempMembers = new Dictionary<(string, MemberType), MemberInfo>();
var methods = new Dictionary<string, MethodInfo[]>();
var castOperators = new Dictionary<(Type, MemberType), MethodInfo>();
var tempMethods = new Dictionary<string, List<MethodInfo>>();
var tempIndexers = new List<PropertyInfo>();
var tempConstructors = new List<ConstructorInfo>();
Expand All @@ -46,13 +42,11 @@ public static TypeInfo Get(Type type) {
break;
}
case MemberTypes.Event: {
var eventInfo = member as EventInfo;
events[eventInfo.Name] = eventInfo;
tempMembers[(member.Name, MemberType.Event)] = member as EventInfo;
break;
}
case MemberTypes.Field: {
var field = member as FieldInfo;
fields[field.Name] = field;
tempMembers[(member.Name, MemberType.Field)] = member as FieldInfo;
break;
}
case MemberTypes.Method: {
Expand All @@ -66,9 +60,9 @@ public static TypeInfo Get(Type type) {
if (parameters.Length == 1 && returnType != typeof(void)) {
var inputType = parameters[0].ParameterType;
if (returnType == type)
castInOperators[inputType] = method;
castOperators[(inputType, MemberType.CastInOperator)] = method;
else if (inputType == type)
castOutOperators[returnType] = method;
castOperators[(returnType, MemberType.CastOutOperator)] = method;
}
break;
}
Expand All @@ -91,25 +85,44 @@ public static TypeInfo Get(Type type) {
tempIndexers.Add(property);
break;
}
properties[property.Name] = property;
tempMembers[(property.Name, MemberType.Property)] = property;
break;
}
case MemberTypes.NestedType: {
subTypes[member.Name] = member as Type;
tempMembers[(member.Name, MemberType.NestedType)] = member as Type;
break;
}
}
foreach (var pair in tempMethods) methods[pair.Key] = pair.Value.ToArray();
indexers = tempIndexers.ToArray();
constructors = tempConstructors.ToArray();
#if NET8_0_OR_GREATER
members = tempMembers.ToFrozenDictionary();
this.castOperators = castOperators.ToFrozenDictionary();
this.methods = methods.ToFrozenDictionary();
#else
members = tempMembers;
this.castOperators = castOperators;
this.methods = methods;
#endif
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
bool TryGet<T>(string name, MemberType memberType, out T member) where T : MemberInfo {
if (members.TryGetValue((name, memberType), out var value)) {
member = value as T;
return true;
}
member = null;
return false;
}

internal bool TryGetValue(object instance, string key, out object value) {
if (properties.TryGetValue(key, out var property) && property.CanRead) {
if (TryGet(key, MemberType.Property, out PropertyInfo property) && property.CanRead) {
value = InternalWrap(property.GetValue(instance));
return true;
}
if (fields.TryGetValue(key, out var field)) {
if (TryGet(key, MemberType.Field, out FieldInfo field)) {
value = InternalWrap(field.GetValue(instance));
return true;
}
Expand All @@ -132,11 +145,11 @@ internal bool TryGetValue(object instance, object[] indexes, out object value) {
}

internal bool TrySetValue(object instance, string key, object value) {
if (properties.TryGetValue(key, out var property) && property.CanWrite) {
if (TryGet(key, MemberType.Property, out PropertyInfo property) && property.CanWrite) {
property.SetValue(InternalUnwrap(instance), value);
return true;
}
if (fields.TryGetValue(key, out var field) && !field.IsInitOnly) {
if (TryGet(key, MemberType.Field, out FieldInfo field) && !field.IsInitOnly) {
field.SetValue(InternalUnwrap(instance), value);
return true;
}
Expand All @@ -155,10 +168,10 @@ internal bool TrySetValue(object instance, object[] indexes, object value) {

internal bool TryGetMethods(string methodName, out MethodInfo[] method) => methods.TryGetValue(methodName, out method);

internal bool TryGetProperties(string propertyName, out PropertyInfo property) => properties.TryGetValue(propertyName, out property);
internal bool TryGetProperties(string propertyName, out PropertyInfo property) => TryGet(propertyName, MemberType.Property, out property);

internal bool TryGetConverter(Type type, bool isIn, out MethodInfo method) =>
(isIn ? castInOperators : castOutOperators).TryGetValue(type, out method);
castOperators.TryGetValue((type, isIn ? MemberType.CastInOperator : MemberType.CastOutOperator), out method);

internal bool TryInvoke(object instance, string methodName, object[] args, out object result, CallInfo callInfo = null) {
var safeArgs = args ?? Array.Empty<object>();
Expand Down Expand Up @@ -200,8 +213,25 @@ internal bool TryConstruct(object[] args, out object result) {
return false;
}

internal bool TryGetSubType(string name, out Type type) => subTypes.TryGetValue(name, out type);
internal bool TryGetSubType(string name, out Type type) => TryGet(name, MemberType.NestedType, out type);

internal bool TryGetEvent(string name, out EventInfo evt) => TryGet(name, MemberType.Event, out evt);

public bool Equals(TypeInfo other) => type == other.type;

public override bool Equals(object obj) => obj is TypeInfo other && Equals(other);

public override int GetHashCode() => type?.GetHashCode() ?? 0;

public override string ToString() => type?.ToString() ?? "(empty)";
}

internal bool TryGetEvent(string name, out EventInfo evt) => events.TryGetValue(name, out evt);
enum MemberType : byte {
Event,
Field,
Property,
NestedType,
CastInOperator,
CastOutOperator,
}
}

0 comments on commit e95ae29

Please sign in to comment.