Skip to content

Commit

Permalink
TargetMember & TargeteMethod support I
Browse files Browse the repository at this point in the history
  • Loading branch information
Sholtee committed Nov 21, 2022
1 parent 69863cb commit bce4e5d
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 166 deletions.
48 changes: 30 additions & 18 deletions SRC/Private/Extensions/Metadata/MemberInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,34 +50,46 @@ private static MemberInfo DoExtractFrom(LambdaExpression expr)
// Can't extract setters from expressions: https://docs.microsoft.com/en-us/dotnet/csharp/misc/cs0832
//

public static ExtendedMemberInfo ExtractFrom(Delegate accessor)
public static ExtendedMemberInfo ExtractFrom(Delegate accessor, int callIndex = 0)
{
MethodInfo method = (MethodInfo) accessor
MethodInfo method = accessor
.Method
.GetInstructions()
.Single(static instruction => instruction.OpCode == OpCodes.Callvirt)!
.Operand;

Type declaringType = method.DeclaringType;
.ConvertAr
(
convert: static instruction => (MethodInfo) instruction.Operand,
drop: static instruction => instruction.OpCode != OpCodes.Callvirt
)[callIndex];

return new ExtendedMemberInfo
(
method,
method.IsSpecialName
? method.Name switch
{
['g', 'e', 't', '_', ..] or ['s', 'e', 't', '_', ..] => declaringType
.GetProperties()
.Single(prop => prop.SetMethod == method || prop.GetMethod == method)!,
['a', 'd', 'd', '_', ..] or ['r', 'e', 'm', 'o', 'v', 'e', '_', ..] => declaringType
.GetEvents()
.Single(evt => evt.AddMethod == method || evt.RemoveMethod == method)!,
_ => throw new NotSupportedException()
}
: method
ExtractFrom(method)
);
}

public static MemberInfo ExtractFrom(MethodInfo method)
{
Type declaringType = method.DeclaringType;

BindingFlags bindingFlags = declaringType.IsInterface
? BindingFlags.Instance | BindingFlags.Public
: BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;

return method.IsSpecialName
? method.Name switch
{
['g', 'e', 't', '_', ..] or ['s', 'e', 't', '_', ..] => declaringType
.GetProperties(bindingFlags)
.Single(prop => prop.SetMethod == method || prop.GetMethod == method)!,
['a', 'd', 'd', '_', ..] or ['r', 'e', 'm', 'o', 'v', 'e', '_', ..] => declaringType
.GetEvents(bindingFlags)
.Single(evt => evt.AddMethod == method || evt.RemoveMethod == method)!,
_ => throw new NotSupportedException()
}
: method;
}

//
// Explicit implementacional a nev "Nevter.Interface.Tag" formaban van
//
Expand Down
16 changes: 14 additions & 2 deletions SRC/Private/InterfaceMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
********************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;

namespace Solti.Utils.Proxy.Internals
Expand All @@ -26,7 +27,18 @@ private static IReadOnlyDictionary<MethodInfo, MethodInfo> GetMappings()

for (int i = 0; i < mapping.InterfaceMethods.Length; i++)
{
dict.Add(mapping.InterfaceMethods[i], mapping.TargetMethods[i]);
try
{
dict.Add(mapping.InterfaceMethods[i], mapping.TargetMethods[i]);
}
catch (Exception ex)
{
//
// We dont wanna a TypeInitializationException to be thrown so eat the exception
//

Trace.TraceWarning($"Cannot register mapping (${mapping.InterfaceMethods[i].Name}): {ex.Message}");
}
}
}

Expand All @@ -36,6 +48,6 @@ private static IReadOnlyDictionary<MethodInfo, MethodInfo> GetMappings()
/// <summary>
/// Returns the cached mappings.
/// </summary>
public static IReadOnlyDictionary<MethodInfo, MethodInfo> Mappings { get; } = GetMappings();
public static IReadOnlyDictionary<MethodInfo, MethodInfo> Value { get; } = GetMappings();
}
}
42 changes: 38 additions & 4 deletions SRC/Private/SyntaxFactories/ProxySyntaxFactory.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,40 @@ ParenthesizedLambdaExpressionSyntax ResolveInvokeTarget(IMethodInfo method, Acti
);
}

/// <summary>
/// InterfaceMap[TInterface, TTarget].Value | null
/// </summary>
#if DEBUG
internal
#else
private
#endif
ExpressionSyntax ResolveInterfaceMap()
{
if (TargetType.IsInterface)
return LiteralExpression(SyntaxKind.NullLiteralExpression);

IGenericTypeInfo map =
(
(IGenericTypeInfo) MetadataTypeInfo.CreateFrom(typeof(InterfaceMap<,>))
).Close(InterfaceType, TargetType);

return MemberAccessExpression
(
SyntaxKind.SimpleMemberAccessExpression,
ResolveType(map),
IdentifierName(nameof(InterfaceMap<object, object>.Value))
);
}

/// <summary>
/// private static readonly MethodContext FXxX = new MethodContext((object target, object[] args) => <br/>
/// { <br/>
/// System.Int32 cb_a = (System.Int32)args[0]; <br/>
/// System.String cb_b; <br/>
/// TT cb_c = (TT)args[2]; <br/>
/// ... <br/>
/// });
/// }, InterfaceMap[TInterface, TTarget].Value | null);
/// </summary>
#if DEBUG
internal
Expand All @@ -263,7 +289,11 @@ FieldDeclarationSyntax ResolveMethodContext(ParenthesizedLambdaExpressionSyntax
$"F{lambda.GetMD5HashCode()}",
ResolveObject<MethodContext>
(
Argument(lambda)
Argument(lambda),
Argument
(
ResolveInterfaceMap()
)
)
);

Expand All @@ -276,7 +306,7 @@ FieldDeclarationSyntax ResolveMethodContext(ParenthesizedLambdaExpressionSyntax
/// System.String cb_b; <br/>
/// T1 cb_c = (T1)args[2]; <br/>
/// ... <br/>
/// }); <br/>
/// }, InterfaceMap[TInterface, TTarget].Value | null); <br/>
/// }
/// </summary>
#if DEBUG
Expand Down Expand Up @@ -318,7 +348,11 @@ ClassDeclarationSyntax ResolveMethodContext(ParenthesizedLambdaExpressionSyntax
$"Value",
ResolveObject<MethodContext>
(
Argument(lambda)
Argument(lambda),
Argument
(
ResolveInterfaceMap()
)
),
@private: false
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@ protected override ClassDeclarationSyntax ResolveMethods(ClassDeclarationSyntax
}

/// <summary>
/// private static readonly MethodContext FXxX = new MethodContext((ITarget target, object[] args) => <br/>
/// private static readonly MethodContext FXxX = new MethodContext((object target, object[] args) => <br/>
/// { <br/>
/// System.Int32 cb_a = (System.Int32) args[0]; <br/>
/// System.String cb_b; <br/>
/// TT cb_c = (TT) args[2]; <br/>
/// System.Object result; <br/>
/// result = target.Foo[TT](cb_a, out cb_b, ref cb_c); <br/>
/// result = ((TInterface) target).Foo[TT](cb_a, out cb_b, ref cb_c); <br/>
/// <br/>
/// args[1] = (System.Object) cb_b; <br/>
/// args[2] = (System.Object) cb_c; <br/>
/// return result; <br/>
/// }); <br/>
/// }, InterfaceMap[TInterface, TTarget].Value | null); <br/>
/// <br/>
/// TResult IInterface.Foo[TGeneric](T1 para1, ref T2 para2, out T3 para3, TGeneric para4) <br/>
/// { <br/>
Expand Down
2 changes: 1 addition & 1 deletion SRC/Public/InvocationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class InvocationContext : MethodContext
/// <summary>
/// Creates a new <see cref="InvocationContext"/> instance.
/// </summary>
public InvocationContext(object?[] args, Func<object, object?[], object?> dispatch): base(dispatch)
public InvocationContext(object?[] args, Func<object, object?[], object?> dispatch): base(dispatch, null)
=> Args = args ?? throw new ArgumentNullException(nameof(args));
#endif
/// <summary>
Expand Down
46 changes: 35 additions & 11 deletions SRC/Public/MethodContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Author: Denes Solti *
********************************************************************************/
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Solti.Utils.Proxy
Expand All @@ -19,16 +20,27 @@ public class MethodContext
/// Creates a new <see cref="MethodContext"/> instance.
/// </summary>
/// <remarks>Calling this constructor is time consuming operation. It is strongly advised to cache the created instances.</remarks>
public MethodContext(Func<object, object?[], object?> dispatch)
public MethodContext(Func<object, object?[], object?> dispatch, IReadOnlyDictionary<MethodInfo, MethodInfo>? mappings)
{
if (dispatch is null)
throw new ArgumentNullException(nameof(dispatch));

ExtendedMemberInfo memberInfo = MemberInfoExtensions.ExtractFrom(dispatch);
ExtendedMemberInfo ifaceMember = MemberInfoExtensions.ExtractFrom(dispatch);

Member = memberInfo.Member;
Method = memberInfo.Method;
InterfaceMember = ifaceMember.Member;
InterfaceMethod = ifaceMember.Method;
Dispatch = dispatch;

if (mappings is not null)
{
TargeteMethod = mappings[InterfaceMethod];
TargetMember = MemberInfoExtensions.ExtractFrom(TargeteMethod);
}
else
{
TargeteMethod = InterfaceMethod;
TargetMember = InterfaceMember;
}
}

/// <summary>
Expand All @@ -39,20 +51,32 @@ protected MethodContext(MethodContext src)
if (src is null)
throw new ArgumentNullException(nameof(src));

Member = src.Member;
Method = src.Method;
Dispatch = src.Dispatch;
InterfaceMember = src.InterfaceMember;
InterfaceMethod = src.InterfaceMethod;
TargetMember = src.TargetMember;
TargeteMethod = src.TargeteMethod;
Dispatch = src.Dispatch;
}

/// <summary>
/// The concrete method behind the <see cref="Member"/>.
/// The concrete method behind the <see cref="InterfaceMember"/>.
/// </summary>
public MethodInfo InterfaceMethod { get; }

/// <summary>
/// The member (property, event or method) that is being invoked.
/// </summary>
public MemberInfo InterfaceMember { get; }

/// <summary>
/// The concrete method behind the <see cref="TargetMember"/>.
/// </summary>
public MethodInfo Method { get; }
public MethodInfo TargeteMethod { get; }

/// <summary>
/// The member (property, event or method) that is being invoked.
/// The member (property, event or method) that is being targeted.
/// </summary>
public MemberInfo Member { get; }
public MemberInfo TargetMember { get; }

/// <summary>
/// Gets the dispatcher function.
Expand Down
51 changes: 1 addition & 50 deletions SRC/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
@@ -1,50 +1 @@
#nullable enable
abstract Solti.Utils.Proxy.Internals.Generator<TInterface, TDescendant>.GetConcreteGenerator() -> Solti.Utils.Proxy.Internals.Generator!
Solti.Utils.Proxy.Attributes.EmbedGeneratedTypeAttribute
Solti.Utils.Proxy.Attributes.EmbedGeneratedTypeAttribute.EmbedGeneratedTypeAttribute(System.Type! generator) -> void
Solti.Utils.Proxy.Attributes.EmbedGeneratedTypeAttribute.Generator.get -> System.Type!
Solti.Utils.Proxy.Generators.DuckGenerator
Solti.Utils.Proxy.Generators.DuckGenerator.DuckGenerator(System.Type! iface, System.Type! target) -> void
Solti.Utils.Proxy.Generators.DuckGenerator.Interface.get -> System.Type!
Solti.Utils.Proxy.Generators.DuckGenerator.Target.get -> System.Type!
Solti.Utils.Proxy.Generators.DuckGenerator<TInterface, TTarget>
Solti.Utils.Proxy.Generators.DuckGenerator<TInterface, TTarget>.DuckGenerator() -> void
Solti.Utils.Proxy.Generators.ProxyGenerator
Solti.Utils.Proxy.Generators.ProxyGenerator.Interceptor.get -> System.Type!
Solti.Utils.Proxy.Generators.ProxyGenerator.Interface.get -> System.Type!
Solti.Utils.Proxy.Generators.ProxyGenerator.ProxyGenerator(System.Type! iface, System.Type! interceptor) -> void
Solti.Utils.Proxy.Generators.ProxyGenerator<TInterface, TInterceptor>
Solti.Utils.Proxy.Generators.ProxyGenerator<TInterface, TInterceptor>.ProxyGenerator() -> void
Solti.Utils.Proxy.InterfaceInterceptor<TInterface>
Solti.Utils.Proxy.InterfaceInterceptor<TInterface>.InterfaceInterceptor(TInterface? target) -> void
Solti.Utils.Proxy.Internals.DuckBase<T>
Solti.Utils.Proxy.Internals.DuckBase<T>.DuckBase(T target) -> void
Solti.Utils.Proxy.Internals.DuckBase<T>.Target.get -> T
Solti.Utils.Proxy.Internals.GeneratedClass
Solti.Utils.Proxy.Internals.GeneratedClass.GeneratedClass() -> void
Solti.Utils.Proxy.Internals.Generator
Solti.Utils.Proxy.Internals.Generator.Activate(object? tuple) -> object!
Solti.Utils.Proxy.Internals.Generator.ActivateAsync(object? tuple, System.Threading.CancellationToken cancellation = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<object!>!
Solti.Utils.Proxy.Internals.Generator.GetGeneratedType() -> System.Type!
Solti.Utils.Proxy.Internals.Generator.GetGeneratedTypeAsync(System.Threading.CancellationToken cancellation = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Type!>!
Solti.Utils.Proxy.Internals.Generator<TInterface, TDescendant>
Solti.Utils.Proxy.Internals.Generator<TInterface, TDescendant>.Generator() -> void
Solti.Utils.Proxy.Internals.TypeEmitter
Solti.Utils.Proxy.InvocationContext
Solti.Utils.Proxy.InvocationContext.Args.get -> object?[]!
Solti.Utils.Proxy.InvocationContext.InvocationContext(object?[]! args, Solti.Utils.Proxy.MethodContext! methodContext) -> void
Solti.Utils.Proxy.InvocationContext.InvocationContext(object?[]! args, System.Func<object!, object?[]!, object?>! dispatch) -> void
Solti.Utils.Proxy.IProxyAccess<TInterface>
Solti.Utils.Proxy.IProxyAccess<TInterface>.Proxy.set -> void
Solti.Utils.Proxy.MethodContext
Solti.Utils.Proxy.MethodContext.Dispatch.get -> System.Func<object!, object?[]!, object?>!
Solti.Utils.Proxy.MethodContext.Member.get -> System.Reflection.MemberInfo!
Solti.Utils.Proxy.MethodContext.Method.get -> System.Reflection.MethodInfo!
Solti.Utils.Proxy.MethodContext.MethodContext(Solti.Utils.Proxy.MethodContext! src) -> void
Solti.Utils.Proxy.MethodContext.MethodContext(System.Func<object!, object?[]!, object?>! dispatch) -> void
static Solti.Utils.Proxy.Internals.GeneratedClass.RegisterInstance(System.Type! instance) -> void
static Solti.Utils.Proxy.Internals.Generator<TInterface, TDescendant>.Activate(object? tuple) -> TInterface
static Solti.Utils.Proxy.Internals.Generator<TInterface, TDescendant>.ActivateAsync(object? tuple, System.Threading.CancellationToken cancellation = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<TInterface>!
static Solti.Utils.Proxy.Internals.Generator<TInterface, TDescendant>.GetGeneratedType() -> System.Type!
static Solti.Utils.Proxy.Internals.Generator<TInterface, TDescendant>.GetGeneratedTypeAsync(System.Threading.CancellationToken cancellation = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Type!>!
static Solti.Utils.Proxy.Internals.Generator<TInterface, TDescendant>.Instance.get -> Solti.Utils.Proxy.Internals.Generator!
#nullable enable
Loading

0 comments on commit bce4e5d

Please sign in to comment.