Added support for custom event delegates that have a return type.

This commit is contained in:
Portikus 2018-02-22 16:23:53 +01:00
Родитель 22dafe66f1
Коммит 75425d5e67
3 изменённых файлов: 79 добавлений и 10 удалений

Просмотреть файл

@ -33,12 +33,21 @@ namespace Etg.SimpleStubs.CodeGen
ParameterSyntax[] parameters = GetEventParameters(eventSymbol, isCustomDelegateEvent);
string onEventArgs;
string eventTriggerArgs;
string methodReturnType = "void";
string customDelegateReturnType = "";
bool hasReturnType = false;
if (isCustomDelegateEvent)
{
IMethodSymbol delegateInvokeMethodSymbol = ((INamedTypeSymbol)(eventSymbol.OriginalDefinition).Type).DelegateInvokeMethod;
onEventArgs = StubbingUtils.FormatParameters(delegateInvokeMethodSymbol);
eventTriggerArgs = onEventArgs;
if (!delegateInvokeMethodSymbol.ReturnsVoid)
{
hasReturnType = true;
customDelegateReturnType = delegateInvokeMethodSymbol.ReturnType.GetFullyQualifiedName();
methodReturnType = $"global::System.Collections.Generic.IEnumerable<{customDelegateReturnType}>";
}
}
else
{
@ -59,25 +68,46 @@ namespace Etg.SimpleStubs.CodeGen
string onEventMethodName = "On_" + eventName;
// Create OnEvent method
MethodDeclarationSyntax onEventMethodDclr = SF.MethodDeclaration(SF.ParseTypeName("void"), onEventMethodName)
BlockSyntax onEventMethodDclrBlock;
if (hasReturnType)
{
onEventMethodDclrBlock = SF.Block(
SF.ParseStatement($"{eventType} handler = {eventName};\n"),
SF.ParseStatement("if (handler == null) {{ yield break; }}\n"),
SF.ParseStatement($"foreach (var listener in handler.GetInvocationList()){{ if (listener.DynamicInvoke({onEventArgs}) is {customDelegateReturnType} ret){{ yield return ret; }} }}"));
}
else
{
onEventMethodDclrBlock = SF.Block(
SF.ParseStatement($"{eventType} handler = {eventName};\n"),
SF.ParseStatement($"if (handler != null) {{ handler({onEventArgs}); }}\n"));
}
MethodDeclarationSyntax onEventMethodDclr = SF.MethodDeclaration(SF.ParseTypeName(methodReturnType), onEventMethodName)
.AddModifiers(SF.Token(SyntaxKind.ProtectedKeyword))
.AddParameterListParameters(parameters)
.WithBody(SF.Block(
SF.ParseStatement($"{eventType} handler = {eventName};\n"),
SF.ParseStatement($"if (handler != null) {{ handler({onEventArgs}); }}\n")
));
.WithBody(onEventMethodDclrBlock);
classDclr = classDclr.AddMembers(onEventMethodDclr);
// Create event trigger method
string eventTriggerMethodName = eventName + "_Raise";
MethodDeclarationSyntax eventTriggerMethod = SF.MethodDeclaration(SF.ParseTypeName("void"),
BlockSyntax eventTriggerMethodBlock;
if (hasReturnType)
{
eventTriggerMethodBlock = SF.Block(SF.ParseStatement($"return {onEventMethodName}({eventTriggerArgs});\n"));
}
else
{
eventTriggerMethodBlock = SF.Block(SF.ParseStatement($"{onEventMethodName}({eventTriggerArgs});\n"));
}
MethodDeclarationSyntax eventTriggerMethod = SF.MethodDeclaration(SF.ParseTypeName(methodReturnType),
eventTriggerMethodName)
.AddModifiers(SF.Token(SyntaxKind.PublicKeyword))
.AddParameterListParameters(parameters)
.WithBody(SF.Block(
SF.ParseStatement($"{onEventMethodName}({eventTriggerArgs});\n")
));
.WithBody(eventTriggerMethodBlock);
classDclr = classDclr.AddMembers(eventTriggerMethod);
return classDclr;

Просмотреть файл

@ -84,7 +84,7 @@ namespace TestClassLibrary
void SetGenericValue<T>(T value);
}
public interface IIgnoredInterface : IDisposable
{
}
@ -126,10 +126,15 @@ namespace TestClassLibrary
}
public delegate void CustomDelegateBasedHandler(int arg1, string arg2, object arg3);
public delegate string CustomDelegateBasedHandlerWithReturnType(object sender, EventArgs eventArgs);
public delegate string CustomDelegateBasedHandlerWithReturnType<T>(T eventArgs);
public interface ICustomDelegateBasedEventExample
{
event CustomDelegateBasedHandler CustomDelegateEventOccurred;
event CustomDelegateBasedHandlerWithReturnType CustomDelegateWithReturnTypeEventOccurred;
event CustomDelegateBasedHandlerWithReturnType<string> CustomDelegateWithReturnTypeWithParameterEventOccurred;
}
}

Просмотреть файл

@ -1,4 +1,6 @@
using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestClassLibrary;
@ -44,5 +46,37 @@ namespace TestClassLibraryTest
Assert.AreEqual("test", arg2);
Assert.AreEqual(typeof(Random), arg3.GetType());
}
[TestMethod]
public void TestCustomDelegateBasedWithReturnTypeEventStub()
{
var stub = new StubICustomDelegateBasedEventExample();
stub.CustomDelegateWithReturnTypeEventOccurred += (sender, args) => "Teststring1";
stub.CustomDelegateWithReturnTypeEventOccurred += (sender, args) => "Teststring2";
stub.CustomDelegateWithReturnTypeEventOccurred += (sender, args) => "Teststring3";
var receivedList = stub.CustomDelegateWithReturnTypeEventOccurred_Raise(stub, EventArgs.Empty).ToList();
Assert.AreEqual(receivedList.Count, 3);
Assert.AreEqual(receivedList[0], "Teststring1");
Assert.AreEqual(receivedList[1], "Teststring2");
Assert.AreEqual(receivedList[2], "Teststring3");
}
[TestMethod]
public void TestCustomDelegateBasedWithReturnTypeWithParameterEventStub()
{
var stub = new StubICustomDelegateBasedEventExample();
stub.CustomDelegateWithReturnTypeWithParameterEventOccurred += args => args + "Teststring1";
stub.CustomDelegateWithReturnTypeWithParameterEventOccurred += args => args + "Teststring2";
stub.CustomDelegateWithReturnTypeWithParameterEventOccurred += args => args + "Teststring3";
var receivedList = stub.CustomDelegateWithReturnTypeWithParameterEventOccurred_Raise("My").ToList();
Assert.AreEqual(receivedList.Count, 3);
Assert.AreEqual(receivedList[0], "MyTeststring1");
Assert.AreEqual(receivedList[1], "MyTeststring2");
Assert.AreEqual(receivedList[2], "MyTeststring3");
}
}
}