Skip to content

Commit

Permalink
Refactoring and add proper assembly info
Browse files Browse the repository at this point in the history
  • Loading branch information
JLChnToZ committed Dec 29, 2023
1 parent 35e4b08 commit 9b5d4c9
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 32 deletions.
8 changes: 8 additions & 0 deletions JLChnToZ.CommonUtils.Dynamic/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Reflection;

[assembly: AssemblyProduct("Limitless")]
[assembly: AssemblyTitle("Limitless")]
[assembly: AssemblyDescription("A simple wrapper library that link up the power of Dynamic Language Runtime (DLR) and reflections.")]
[assembly: AssemblyCompany("Explosive Theorem Lab")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
26 changes: 9 additions & 17 deletions JLChnToZ.CommonUtils.Dynamic/Delegates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ namespace JLChnToZ.CommonUtils.Dynamic {
/// <summary>
/// Provides methods to bind methods, properties, converters and operators to delegates, regardness of its visibility.
/// </summary>
/// <remarks>
/// Using delegates are more efficient than using reflection and dynamic objects.
/// Recommend stick to delegates unless your usage is too complex to be handled by delegates such as working on temporary instances.
/// </remarks>
public static class Delegates {
static readonly Dictionary<(Type srcType, Type destType, Type delegateType), Delegate> converterCache =
new Dictionary<(Type, Type, Type), Delegate>();
Expand Down Expand Up @@ -112,23 +116,15 @@ public static TDelegate BindProperty<T, TDelegate>(T target = default, string pr
BindProperty(typeof(T), DEFAULT_FLAGS, propertyName, typeof(TDelegate), target) as TDelegate;

static Delegate BindMethod(Type type, string methodName, BindingFlags bindingFlags, Type delegateType, object target = null) =>
TypeInfo.Get(type).TryGetMethods(methodName, out var methods) ? BindMethod(
TypeInfo.Get(type).TryGetMethods(methodName, out var methods) &&
TryGetDelegateSignature(delegateType, out var parameters, out _) ? BindMethod(
type, delegateType,
Type.DefaultBinder.SelectMethod(
bindingFlags, methods,
Array.ConvertAll(
delegateType.GetMethod("Invoke").GetParameters(),
GetParameterType
),
null
) as MethodInfo,
Type.DefaultBinder.SelectMethod(bindingFlags, methods, parameters, null) as MethodInfo,
target
) : null;

static Delegate BindProperty(Type type, BindingFlags bindingFlags, string propertyName, Type delegateType, object target = null) {
var invokeMethod = delegateType.GetMethod("Invoke");
var returnType = invokeMethod.ReturnType;
var parameters = Array.ConvertAll(invokeMethod.GetParameters(), GetParameterType);
if (!TryGetDelegateSignature(delegateType, out var parameters, out var returnType)) return null;
bool isSetterRequested = returnType == typeof(void);
if (isSetterRequested) {
if (parameters.Length == 0) return null;
Expand Down Expand Up @@ -160,8 +156,6 @@ static Delegate BindMethod(Type targetType, Type delegateType, MethodInfo method
}
return Delegate.CreateDelegate(delegateType, target, method, false);
}

static Type GetParameterType(ParameterInfo parameter) => parameter.ParameterType;
#endregion

#region Bind Converters
Expand Down Expand Up @@ -197,9 +191,7 @@ public static Delegate BindConverter(Type srcType, Type destType, Type delegateT
if (destType == null) throw new ArgumentNullException(nameof(destType));
if (delegateType != null) {
if (!delegateType.IsSubclassOf(typeof(Delegate))) throw new ArgumentException($"Type {delegateType} is not a delegate type");
var invokeMethod = delegateType.GetMethod("Invoke");
var parameters = invokeMethod.GetParameters();
if (parameters.Length != 1 || parameters[0].ParameterType != srcType || invokeMethod.ReturnType != destType)
if (!TryGetDelegateSignature(delegateType, out var parameters, out var returnType) || parameters.Length != 1 || returnType != destType)
throw new ArgumentException($"Delegate type {delegateType} is not compatible with converter from {srcType} to {destType}");
}
return BindConverterUnchecked(srcType, destType, delegateType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>

</Project>
1 change: 1 addition & 0 deletions JLChnToZ.CommonUtils.Dynamic/LimitlessEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace JLChnToZ.CommonUtils.Dynamic {
using static Utilites;

/// <summary>Special dynamic object that can be used to access events.</summary>
/// <remarks>This should not be directly used. Use <see cref="Limitless"/> instead.</remarks>
public class LimitlessEvent: LimitlessInvokable {
Expand Down
8 changes: 3 additions & 5 deletions JLChnToZ.CommonUtils.Dynamic/LimitlessInvokable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,11 @@ public Delegate CreateDelegate(Type delegateType) {

internal protected bool TryCreateDelegate(Type delegateType, out Delegate result) {
if (delegateType.IsSubclassOf(typeof(Delegate))) {
var invokeMethod = delegateType.GetMethod("Invoke");
if (invokeMethod != null) {
if (TryGetDelegateSignature(delegateType, out var parameters, out var returnType)) {
var matched = Type.DefaultBinder.SelectMethod(
DEFAULT_FLAGS, MethodInfos,
Array.ConvertAll(invokeMethod.GetParameters(), GetParameterType), null
DEFAULT_FLAGS, MethodInfos, parameters, null
) as MethodInfo;
if (matched != null && matched.ReturnType == invokeMethod.ReturnType) {
if (matched != null && matched.ReturnType == returnType) {
var target = InvokeTarget;
if (matched.IsStatic) {
result = Delegate.CreateDelegate(delegateType, matched, false);
Expand Down
17 changes: 9 additions & 8 deletions JLChnToZ.CommonUtils.Dynamic/TypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,14 @@ public static TypeInfo Get(Type type) {
properties[property.Name] = property;
break;
}
case MemberTypes.NestedType: {
subTypes[member.Name] = member as Type;
break;
}
}
foreach (var pair in tempMethods) methods[pair.Key] = pair.Value.ToArray();
indexers = tempIndexers.ToArray();
constructors = tempConstructors.ToArray();
foreach (var t in type.GetNestedTypes(DEFAULT_FLAGS)) subTypes[t.Name] = t;
}

internal bool TryGetValue(object instance, string key, out object value) {
Expand Down Expand Up @@ -125,7 +128,7 @@ internal bool TryGetValue(object instance, object[] indexes, out object value) {
if (matched != null) {
value = InternalWrap(matched.GetValue(instance, InternalUnwrap(
indexes, binder,
Array.ConvertAll(matched.GetIndexParameters(), GetParameterType)
matched.GetIndexParameters().ToParameterTypes()
)));
return true;
}
Expand Down Expand Up @@ -154,7 +157,7 @@ internal bool TrySetValue(object instance, object[] indexes, object value) {
if (matched != null) {
matched.SetValue(InternalUnwrap(instance), value, InternalUnwrap(
indexes, binder,
Array.ConvertAll(matched.GetIndexParameters(), GetParameterType)
matched.GetIndexParameters().ToParameterTypes()
));
return true;
}
Expand All @@ -165,10 +168,8 @@ internal bool TrySetValue(object instance, object[] indexes, object value) {

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

internal bool TryGetConverter(Type type, bool isIn, out MethodInfo method) {
if (isIn) return castInOperators.TryGetValue(type, out method);
return castOutOperators.TryGetValue(type, out method);
}
internal bool TryGetConverter(Type type, bool isIn, out MethodInfo method) =>
(isIn ? castInOperators : castOutOperators).TryGetValue(type, out method);

internal bool TryInvoke(object instance, string methodName, object[] args, out object result) {
var safeArgs = args;
Expand All @@ -193,7 +194,7 @@ internal bool TryCast(object instance, Type type, bool isIn, out object result)
result = instance;
return true;
}
if ((isIn ? castInOperators : castOutOperators).TryGetValue(type, out var method)) {
if (TryGetConverter(type, isIn, out var method)) {
result = method.Invoke(null, new[] { instance });
return true;
}
Expand Down
23 changes: 21 additions & 2 deletions JLChnToZ.CommonUtils.Dynamic/Utilites.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static bool TryGetMatchingMethod<T>(T[] methodInfos, ref object[] args, o
var matched = binder.SelectMethod(DEFAULT_FLAGS, methodInfos, Array.ConvertAll(args, GetUndelyType), null);
if (matched != null) {
bestMatches = (T)matched;
args = InternalUnwrap(args, binder, Array.ConvertAll(matched.GetParameters(), GetParameterType));
args = InternalUnwrap(args, binder, matched.GetParameters().ToParameterTypes());
return true;
}
bestMatches = null;
Expand All @@ -58,7 +58,26 @@ public static Type GetUndelyType(object obj) {
return obj.GetType();
}

public static Type GetParameterType(ParameterInfo parameterInfo) => parameterInfo.ParameterType;
public static bool TryGetDelegateSignature(Type delegateType, out Type[] parameters, out Type returnType) {
if (delegateType == null) {
parameters = null;
returnType = null;
return false;
}
var invokeMethod = delegateType.GetMethod("Invoke");
if (invokeMethod == null) {
parameters = null;
returnType = null;
return false;
}
parameters = invokeMethod.GetParameters().ToParameterTypes();
returnType = invokeMethod.ReturnType;
return true;
}

public static Type[] ToParameterTypes(this ParameterInfo[] parameterInfos) => Array.ConvertAll(parameterInfos, GetParameterType);

static Type GetParameterType(ParameterInfo parameterInfo) => parameterInfo.ParameterType;

public static string ToOperatorMethodName(this ExpressionType expressionType) {
switch (expressionType) {
Expand Down

0 comments on commit 9b5d4c9

Please sign in to comment.