Browse Source

Add 'SD.MainThread.InvokeAsyncAndForget()' method that combines 'InvokeAsync().FireAndForget()' into a single step.

This makes debugging SharpDevelop easier because exceptions are left unhandled; they don't get caught by a Task<T>.
newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
22e4ec0457
  1. 20
      samples/PortSD4AddInToSD5/WorkbenchSingletonIssueProvider.cs
  2. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs
  3. 19
      src/Main/Base/Project/Services/IMessageLoop.cs
  4. 29
      src/Main/Base/Test/Utils/FakeMessageLoop.cs
  5. 9
      src/Main/SharpDevelop/Parser/LoadSolutionProjects.cs
  6. 16
      src/Main/SharpDevelop/Services/DispatcherMessageLoop.cs

20
samples/PortSD4AddInToSD5/WorkbenchSingletonIssueProvider.cs

@ -11,6 +11,7 @@ using System.Collections.Generic; @@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.SharpDevelop;
@ -102,8 +103,7 @@ namespace PortSD4AddInToSD5 @@ -102,8 +103,7 @@ namespace PortSD4AddInToSD5
script => {
script.Replace(invocationExpression,
new IdentifierExpression("SD").Member("MainThread")
.Invoke("InvokeAsync", arg)
.Invoke("FireAndForget"));
.Invoke("InvokeAsyncAndForget", arg));
});
break;
}
@ -122,6 +122,22 @@ namespace PortSD4AddInToSD5 @@ -122,6 +122,22 @@ namespace PortSD4AddInToSD5
});
break;
}
case "ICSharpCode.SharpDevelop.IMessageLoop.InvokeAsync":
// We used to recommend SD.MainThread.InvokeAsync(...).FireAndForget(),
// but it's better to use SD.MainThread.InvokeAsyncAndForget(...)
if (invocationExpression.Clone().Invoke("FireAndForget").IsMatch(invocationExpression.Parent.Parent)) {
var ident = invocationExpression.Parent.GetChildByRole(Roles.Identifier);
yield return new CodeIssue(
"Use InvokeAsyncAndForget() instead",
ident.StartLocation, ident.EndLocation,
new CodeAction("Use InvokeAsyncAndForget() instead",
script => {
var newInvocation = (InvocationExpression)invocationExpression.Clone();
((MemberReferenceExpression)newInvocation.Target).MemberName = "InvokeAsyncAndForget";
script.Replace(invocationExpression.Parent.Parent, newInvocation);
}));
}
break;
}
}
}

2
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs

@ -124,6 +124,8 @@ namespace CSharpBinding.Refactoring @@ -124,6 +124,8 @@ namespace CSharpBinding.Refactoring
if (resultForFile != null) {
callback(resultForFile);
}
} catch (IOException) {
// ignore IO exceptions (e.g. a file is missing)
} catch (OperationCanceledException) {
throw;
} catch (Exception ex) {

19
src/Main/Base/Project/Services/IMessageLoop.cs

@ -18,7 +18,7 @@ namespace ICSharpCode.SharpDevelop @@ -18,7 +18,7 @@ namespace ICSharpCode.SharpDevelop
public interface IMessageLoop
{
/// <summary>
/// Gets the thread corresponding to this message loop.
/// Gets the thread that runs this message loop.
/// </summary>
Thread Thread { get; }
@ -77,9 +77,12 @@ namespace ICSharpCode.SharpDevelop @@ -77,9 +77,12 @@ namespace ICSharpCode.SharpDevelop
T InvokeIfRequired<T>(Func<T> callback, DispatcherPriority priority, CancellationToken cancellationToken);
/// <summary>
/// Invokes the specified callback.
/// Invokes the specified callback on the message loop.
/// </summary>
/// <returns>Returns a task that is signalled when the execution of the callback is completed.</returns>
/// <remarks>
/// If the callback method causes an exception; the exception gets stored in the task object.
/// </remarks>
Task InvokeAsync(Action callback);
/// <inheritdoc see="InvokeAsync(Action)"/>
Task InvokeAsync(Action callback, DispatcherPriority priority);
@ -93,6 +96,18 @@ namespace ICSharpCode.SharpDevelop @@ -93,6 +96,18 @@ namespace ICSharpCode.SharpDevelop
/// <inheritdoc see="InvokeAsync(Action)"/>
Task<T> InvokeAsync<T>(Func<T> callback, DispatcherPriority priority, CancellationToken cancellationToken);
/// <summary>
/// Invokes the specified callback on the message loop.
/// </summary>
/// <remarks>
/// This method does not wait for the callback complete execution.
/// If this method is used on the main thread; the message loop must be pumped before the callback gets to run.
/// If the callback causes an exception, it is left unhandled.
/// </remarks>
void InvokeAsyncAndForget(Action callback);
/// <inheritdoc see="InvokeAsyncAndForget(Action)"/>
void InvokeAsyncAndForget(Action callback, DispatcherPriority priority);
/// <summary>
/// Waits <paramref name="delay"/>, then executed <paramref name="method"/> on the message loop thread.
/// </summary>

29
src/Main/Base/Test/Utils/FakeMessageLoop.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace ICSharpCode.SharpDevelop
{
@ -19,7 +20,7 @@ namespace ICSharpCode.SharpDevelop @@ -19,7 +20,7 @@ namespace ICSharpCode.SharpDevelop
}
}
public System.Windows.Threading.Dispatcher Dispatcher {
public Dispatcher Dispatcher {
get {
throw new NotImplementedException();
}
@ -55,12 +56,12 @@ namespace ICSharpCode.SharpDevelop @@ -55,12 +56,12 @@ namespace ICSharpCode.SharpDevelop
callback();
}
public void InvokeIfRequired(Action callback, System.Windows.Threading.DispatcherPriority priority)
public void InvokeIfRequired(Action callback, DispatcherPriority priority)
{
callback();
}
public void InvokeIfRequired(Action callback, System.Windows.Threading.DispatcherPriority priority, CancellationToken cancellationToken)
public void InvokeIfRequired(Action callback, DispatcherPriority priority, CancellationToken cancellationToken)
{
callback();
}
@ -70,12 +71,12 @@ namespace ICSharpCode.SharpDevelop @@ -70,12 +71,12 @@ namespace ICSharpCode.SharpDevelop
return callback();
}
public T InvokeIfRequired<T>(Func<T> callback, System.Windows.Threading.DispatcherPriority priority)
public T InvokeIfRequired<T>(Func<T> callback, DispatcherPriority priority)
{
return callback();
}
public T InvokeIfRequired<T>(Func<T> callback, System.Windows.Threading.DispatcherPriority priority, CancellationToken cancellationToken)
public T InvokeIfRequired<T>(Func<T> callback, DispatcherPriority priority, CancellationToken cancellationToken)
{
return callback();
}
@ -85,12 +86,12 @@ namespace ICSharpCode.SharpDevelop @@ -85,12 +86,12 @@ namespace ICSharpCode.SharpDevelop
throw new NotImplementedException();
}
public Task InvokeAsync(Action callback, System.Windows.Threading.DispatcherPriority priority)
public Task InvokeAsync(Action callback, DispatcherPriority priority)
{
throw new NotImplementedException();
}
public Task InvokeAsync(Action callback, System.Windows.Threading.DispatcherPriority priority, CancellationToken cancellationToken)
public Task InvokeAsync(Action callback, DispatcherPriority priority, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
@ -100,12 +101,22 @@ namespace ICSharpCode.SharpDevelop @@ -100,12 +101,22 @@ namespace ICSharpCode.SharpDevelop
throw new NotImplementedException();
}
public Task<T> InvokeAsync<T>(Func<T> callback, System.Windows.Threading.DispatcherPriority priority)
public Task<T> InvokeAsync<T>(Func<T> callback, DispatcherPriority priority)
{
throw new NotImplementedException();
}
public Task<T> InvokeAsync<T>(Func<T> callback, System.Windows.Threading.DispatcherPriority priority, CancellationToken cancellationToken)
public Task<T> InvokeAsync<T>(Func<T> callback, DispatcherPriority priority, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void InvokeAsyncAndForget(Action callback)
{
throw new NotImplementedException();
}
public void InvokeAsyncAndForget(Action callback, DispatcherPriority priority)
{
throw new NotImplementedException();
}

9
src/Main/SharpDevelop/Parser/LoadSolutionProjects.cs

@ -40,11 +40,10 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -40,11 +40,10 @@ namespace ICSharpCode.SharpDevelop.Parser
void RaiseThreadStarted()
{
threadRunningTime = Stopwatch.StartNew();
SD.MainThread.InvokeAsync(
delegate {
IsRunning = true;
Started(this, EventArgs.Empty);
}).FireAndForget();
SD.MainThread.InvokeAsyncAndForget(delegate {
IsRunning = true;
Started(this, EventArgs.Empty);
});
}
void RaiseThreadEnded()

16
src/Main/SharpDevelop/Services/DispatcherMessageLoop.cs

@ -128,15 +128,25 @@ namespace ICSharpCode.SharpDevelop @@ -128,15 +128,25 @@ namespace ICSharpCode.SharpDevelop
return dispatcher.InvokeAsync(callback, priority, cancellationToken).Task;
}
public void InvokeAsyncAndForget(Action callback)
{
dispatcher.BeginInvoke(callback);
}
public void InvokeAsyncAndForget(Action callback, DispatcherPriority priority)
{
dispatcher.BeginInvoke(callback, priority);
}
public async void CallLater(TimeSpan delay, Action method)
{
await Task.Delay(delay).ConfigureAwait(false);
InvokeAsync(method).FireAndForget();
InvokeAsyncAndForget(method);
}
IAsyncResult ISynchronizeInvoke.BeginInvoke(Delegate method, object[] args)
{
return dispatcher.InvokeAsync<object>(() => method.DynamicInvoke(args)).Task;
return dispatcher.BeginInvoke(method, args).Task;
}
object ISynchronizeInvoke.EndInvoke(IAsyncResult result)
@ -146,7 +156,7 @@ namespace ICSharpCode.SharpDevelop @@ -146,7 +156,7 @@ namespace ICSharpCode.SharpDevelop
object ISynchronizeInvoke.Invoke(Delegate method, object[] args)
{
return dispatcher.Invoke(() => method.DynamicInvoke(args));
return dispatcher.Invoke(method, args);
}
}
}

Loading…
Cancel
Save