Skip to content

Commit

Permalink
introducing EventInterceptorFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
Sholtee committed Jun 14, 2020
1 parent e23a611 commit eb16843
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 75 deletions.
150 changes: 91 additions & 59 deletions SRC/Private/SyntaxFactories/ProxySyntaxFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,6 @@ public IEnumerable<MemberDeclarationSyntax> Build()
}
}


/// <summary>
/// private static readonly PropertyInfo FItem = Properties["IInterface.Item"]; <br/>
/// <br/>
Expand Down Expand Up @@ -811,63 +810,95 @@ public IndexedPropertyInterceptorFactory(PropertyInfo property, ProxySyntaxFacto
}

/// <summary>
/// private static readonly EventInfo FEvent = Events["IInterface.Event"]; <br/>
/// <br/>
/// event EventType IInterface.Event <br/>
/// { <br/>
/// add <br/>
/// { <br/>
/// object result = Invoke(FEvent.AddMethod, new object[]{ value }, FEvent); <br/>
/// if (result == CALL_TARGET) Target.Event += value; <br/>
/// } <br/>
/// remove <br/>
/// { <br/>
/// object result = Invoke(FEvent.RemoveMethod, new object[]{ value }, FEvent); <br/>
/// if (result == CALL_TARGET) Target.Event -= value; <br/>
/// } <br/>
/// private static readonly EventInfo FEvent = Events["IInterface.Event"]; <br/>
/// <br/>
/// event EventType IInterface.Event <br/>
/// { <br/>
/// add <br/>
/// { <br/>
/// InvokeTarget = () => Target.Event += value; <br/>
/// Invoke(FEvent.AddMethod, new object[]{ value }, FEvent); <br/>
/// } <br/>
/// remove <br/>
/// { <br/>
/// InvokeTarget = () => Target.Event -= value; <br/>
/// Invoke(FEvent.RemoveMethod, new object[]{ value }, FEvent); <br/>
/// } <br/>
/// }
/// </summary>
internal IEnumerable<MemberDeclarationSyntax> GenerateProxyEvent(EventInfo ifaceEvent)
public sealed class EventInterceptorFactory
{
IdentifierNameSyntax fieldName = GenerateFieldName(ifaceEvent);
public EventInfo Event { get; }

public IdentifierNameSyntax RelatedField { get; }

yield return DeclareField<EventInfo>(fieldName, EVENTS, ifaceEvent);
public ProxySyntaxFactory<TInterface, TInterceptor> Owner { get; }

public EventInterceptorFactory(EventInfo @event, ProxySyntaxFactory<TInterface, TInterceptor> owner)
{
Event = @event;
RelatedField = GenerateFieldName(@event);
Owner = owner;
}

yield return DeclareEvent
/// <summary>
/// () => Target.Event [+|-]= value;
/// </summary>
internal LambdaExpressionSyntax BuildRegister(bool add) => ParenthesizedLambdaExpression
(
@event: ifaceEvent,
addBody: Block(AddBody()),
removeBody: Block(RemoveBody())
RegisterEvent(Event, TARGET, add)
);

IEnumerable<StatementSyntax> AddBody()
{
LocalDeclarationStatementSyntax result = CallInvoke
/// <summary>
/// this.Invoke(FEvent.AddMethod, new System.Object[]{ value }, FEvent);
/// </summary>
internal StatementSyntax CallInvoke(bool add) => ExpressionStatement
(
InvokeMethod
(
nameof(result),
StaticMemberAccess(fieldName, nameof(EventInfo.AddMethod)), // FEvent.AddMethod,
CreateArray<object>(IdentifierName(Value)), // new object[] {value}
StaticMemberName(fieldName) //FEvent
);
INVOKE,
target: null,
castTargetTo: null,
arguments: new ExpressionSyntax[]
{
Owner.StaticMemberAccess(RelatedField, add ? nameof(EventInfo.AddMethod) : nameof(EventInfo.RemoveMethod)), // FEvent.[Add|Remove]Method
CreateArray<object>(IdentifierName(Value)),
Owner.StaticMemberName(RelatedField) // FEvent
}.Select(Argument).ToArray()
)
);

yield return result;
yield return ShouldCallTarget(result,
ifTrue: ExpressionStatement(expression: RegisterEvent(ifaceEvent, TARGET, add: true)));
}
/// <summary>
/// InvokeTarget = () => ...;
/// </summary>
private static StatementSyntax AssignCallback(LambdaExpressionSyntax lambda) => ExpressionStatement
(
expression: AssignmentExpression
(
kind: SyntaxKind.SimpleAssignmentExpression,
left: PropertyAccess(INVOKE_TARGET, null),
right: lambda
)
);

IEnumerable<StatementSyntax> RemoveBody()
public IEnumerable<MemberDeclarationSyntax> Build()
{
LocalDeclarationStatementSyntax result = CallInvoke
yield return DeclareField<EventInfo>(RelatedField, EVENTS, Event);

yield return DeclareEvent
(
nameof(result),
StaticMemberAccess(fieldName, nameof(EventInfo.RemoveMethod)), // FEvent.RemoveMethod
CreateArray<object>(IdentifierName(Value)),
StaticMemberName(fieldName)
@event: Event,
addBody: Block
(
AssignCallback(BuildRegister(add: true)),
CallInvoke(add: true)
),
removeBody: Block
(
AssignCallback(BuildRegister(add: false)),
CallInvoke(add: false)
)
);

yield return result;
yield return ShouldCallTarget(result,
ifTrue: ExpressionStatement(expression: RegisterEvent(ifaceEvent, TARGET, add: false)));
}
}
#endregion
Expand Down Expand Up @@ -919,21 +950,22 @@ protected internal override ClassDeclarationSyntax GenerateProxyClass()
.Select(m => new MethodInterceptorFactory(m).Build())
);

/* members.AddRange
(
interfaceType
.ListMembers<PropertyInfo>()
.Where(p => !implementedInterfaces.Contains(p.DeclaringType))
.SelectMany(GenerateProxyProperty)
);
*/
members.AddRange
(
interfaceType
.ListMembers<EventInfo>()
.Where(e => !implementedInterfaces.Contains(e.DeclaringType))
.SelectMany(GenerateProxyEvent)
);
/* members.AddRange
(
interfaceType
.ListMembers<PropertyInfo>()
.Where(p => !implementedInterfaces.Contains(p.DeclaringType))
.SelectMany(GenerateProxyProperty)
);
members.AddRange
(
interfaceType
.ListMembers<EventInfo>()
.Where(e => !implementedInterfaces.Contains(e.DeclaringType))
.SelectMany(GenerateProxyEvent)
);
*/

return cls.WithMembers(List(members));
}
Expand Down
24 changes: 9 additions & 15 deletions TEST/EventSrc.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
class GeneratedProxy
event Solti.Utils.Proxy.SyntaxFactories.Tests.ProxySyntaxFactoryTestsBase.TestDelegate<System.Int32> Solti.Utils.Proxy.SyntaxFactories.Tests.ProxySyntaxFactoryTestsBase.IFoo<System.Int32>.Event
{
private static readonly System.Reflection.EventInfo FEvent0 = Solti.Utils.Proxy.InterfaceInterceptor<Solti.Utils.Proxy.SyntaxFactories.Tests.ProxySyntaxFactoryTestsBase.IFoo<System.Int32>>.Events["Solti.Utils.Proxy.SyntaxFactories.Tests.ProxySyntaxFactoryTestsBase.IFoo<System.Int32>.Event"];
event Solti.Utils.Proxy.SyntaxFactories.Tests.ProxySyntaxFactoryTestsBase.TestDelegate<System.Int32> Solti.Utils.Proxy.SyntaxFactories.Tests.ProxySyntaxFactoryTestsBase.IFoo<System.Int32>.Event
add
{
add
{
System.Object result = this.Invoke(GeneratedProxy.FEvent0.AddMethod, new System.Object[]{value}, GeneratedProxy.FEvent0);
if (result == this.CALL_TARGET)
this.Target.Event += value;
}
this.InvokeTarget = () => this.Target.Event += value;
this.Invoke(GeneratedProxy.FEvent0.AddMethod, new System.Object[]{value}, GeneratedProxy.FEvent0);
}

remove
{
System.Object result = this.Invoke(GeneratedProxy.FEvent0.RemoveMethod, new System.Object[]{value}, GeneratedProxy.FEvent0);
if (result == this.CALL_TARGET)
this.Target.Event -= value;
}
remove
{
this.InvokeTarget = () => this.Target.Event -= value;
this.Invoke(GeneratedProxy.FEvent0.RemoveMethod, new System.Object[]{value}, GeneratedProxy.FEvent0);
}
}
2 changes: 1 addition & 1 deletion TEST/SyntaxFactories/ProxySyntaxFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ public void AcquireMethodInfo_ShouldGetAMethodInfoInstance((MethodInfo Method, i

[Test]
public void GenerateProxyEvent_Test() =>
Assert.That(SyntaxFactory.ClassDeclaration(Generator.GeneratedClassName).WithMembers(SyntaxFactory.List(Generator.GenerateProxyEvent(Event))).NormalizeWhitespace(eol: "\n").ToString(), Is.EqualTo(File.ReadAllText("EventSrc.txt")));
Assert.That(new EventInterceptorFactory(Event, new Internals.ProxySyntaxFactory<IFoo<int>, FooInterceptor>()).Build().Last().NormalizeWhitespace(eol: "\n").ToFullString(), Is.EqualTo(File.ReadAllText("EventSrc.txt")));

[Test]
public void BuildPropertyGetter_ShouldCreateTheProperLambda() =>
Expand Down

0 comments on commit eb16843

Please sign in to comment.