Skip to content

Commit

Permalink
Add 'SD.MainThread.InvokeAsyncAndForget()' method that combines 'Invo…
Browse files Browse the repository at this point in the history
…keAsync().FireAndForget()' into a single step.

This makes debugging SharpDevelop easier because exceptions are left unhandled; they don't get caught by a Task<T>.
  • Loading branch information
dgrunwald committed Jan 27, 2013
1 parent 0ca73ec commit 22e4ec0
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 21 deletions.
20 changes: 18 additions & 2 deletions samples/PortSD4AddInToSD5/WorkbenchSingletonIssueProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
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;
Expand Down Expand Up @@ -102,8 +103,7 @@ public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
script => {
script.Replace(invocationExpression,
new IdentifierExpression("SD").Member("MainThread")
.Invoke("InvokeAsync", arg)
.Invoke("FireAndForget"));
.Invoke("InvokeAsyncAndForget", arg));
});
break;
}
Expand All @@ -122,6 +122,22 @@ public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
});
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;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ void SearchForIssuesParallel(List<FileName> fileNames, IEnumerable<IssueManager.
if (resultForFile != null) {
callback(resultForFile);
}
} catch (IOException) {
// ignore IO exceptions (e.g. a file is missing)
} catch (OperationCanceledException) {
throw;
} catch (Exception ex) {
Expand Down
19 changes: 17 additions & 2 deletions src/Main/Base/Project/Services/IMessageLoop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down Expand Up @@ -77,9 +77,12 @@ public interface IMessageLoop
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);
Expand All @@ -93,6 +96,18 @@ public interface IMessageLoop
/// <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>
Expand Down
29 changes: 20 additions & 9 deletions src/Main/Base/Test/Utils/FakeMessageLoop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;

namespace ICSharpCode.SharpDevelop
{
Expand All @@ -19,7 +20,7 @@ public Thread Thread {
}
}

public System.Windows.Threading.Dispatcher Dispatcher {
public Dispatcher Dispatcher {
get {
throw new NotImplementedException();
}
Expand Down Expand Up @@ -55,12 +56,12 @@ public void InvokeIfRequired(Action callback)
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();
}
Expand All @@ -70,12 +71,12 @@ public T InvokeIfRequired<T>(Func<T> callback)
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();
}
Expand All @@ -85,12 +86,12 @@ public Task InvokeAsync(Action callback)
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();
}
Expand All @@ -100,12 +101,22 @@ public Task<T> InvokeAsync<T>(Func<T> callback)
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();
}
Expand Down
9 changes: 4 additions & 5 deletions src/Main/SharpDevelop/Parser/LoadSolutionProjects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,10 @@ public LoadSolutionProjects()
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()
Expand Down
16 changes: 13 additions & 3 deletions src/Main/SharpDevelop/Services/DispatcherMessageLoop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,25 @@ public Task<T> InvokeAsync<T>(Func<T> callback, DispatcherPriority priority, Can
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)
Expand All @@ -146,7 +156,7 @@ object ISynchronizeInvoke.EndInvoke(IAsyncResult result)

object ISynchronizeInvoke.Invoke(Delegate method, object[] args)
{
return dispatcher.Invoke(() => method.DynamicInvoke(args));
return dispatcher.Invoke(method, args);
}
}
}

0 comments on commit 22e4ec0

Please sign in to comment.