I would like to ask how to convert a method so that it can return any type depending on what happens within it.
What I have is the start of an application which will visit a number of webpages (and ultimately perform some tasks on each) before moving on to the next.
At the minute I have this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
namespace WindowsFormsApplication12
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
webBrowser1.ScriptErrorsSuppressed = true;
label1.MaximumSize = new Size(100, 0);
label1.AutoSize = true;
}
private void go_Click(object sender, EventArgs e)
{
ProcessUrlsAsync(new[] { "http://google.com", "http://microsoft.com", "http://yahoo.com" }).Start();
}
private void Exit(object sender, EventArgs e)
{
Application.Exit();
}
private Task ProcessUrlsAsync(string[] urls)
{
return new Task(() =>
{
foreach (string url in urls)
{
TaskAwaiter<string> awaiter = ProcessUrlAsync(url);
string result = awaiter.GetResult();
label1.Invoke((MethodInvoker)(() => label1.Text = result));
}
});
}
private Task ProcessUrlsAsync(string url)
{
return new Task(() =>
{
TaskAwaiter<string> awaiter = ProcessUrlAsync(url);
string result = awaiter.GetResult();
MessageBox.Show(result);
});
}
private TaskAwaiter<string> LoadWebPage(string url)
{
TaskCompletionSource<string> taskCompletionSource = new TaskCompletionSource<string>();
var handler = new WebBrowserDocumentCompletedEventHandler((s, e) =>
{
if (e.Url.Equals(url))
{
taskCompletionSource.SetResult(e.Url.ToString());
}
else
{
taskCompletionSource.SetResult(e.Url + ": " + webBrowser1.Document.Title);
}
});
webBrowser1.DocumentCompleted += handler;
taskCompletionSource.Task.ContinueWith(s => { webBrowser1.DocumentCompleted -= handler; });
webBrowser1.Navigate(url);
return taskCompletionSource.Task.GetAwaiter();
}
}
}
What I'd like to do is change the
private TaskAwaiter<string> LoadWebPage(string url)
method so that it returns a TaskAwaiter< generic type >. My reason for this is that if it fails to log in or an error occurs whilst processing, then I can return a boolean or a string or an int to signify the success (or not) of the actions being performed.
I initially thought of overloading the method until I realised this would not work with different return types, doh!!
The references to the web pages are only there as a test to make sure I can get the basics of opening a web page. Once I have this, these will be replaced with my systems web pages before I can start processing.
Is it possible to convert this method in this way?
Edit: I like the look of @Bjarke Søgaard's solution so am trying to implement it.
Unfortunately I'm being a little dense at this time of night and for the life of me cannot work out how to use within the method. So far I have this:
TaskAwaiter<WebResponse> awaiter = LoadWebPage(url);
private TaskAwaiter<WebResponse> LoadWebPage(string url)
{
TaskCompletionSource<WebResponse> taskCompletionSource = new TaskCompletionSource<WebResponse>();
var handler = new WebBrowserDocumentCompletedEventHandler((s, e) =>
{
//taskCompletionSource.SetResult(e.Url + ": " + webBrowser1.Document.Title);
taskCompletionSource.SetResult(<< Stuck Here >>);
});
webBrowser1.DocumentCompleted += handler;
taskCompletionSource.Task.ContinueWith(s => { webBrowser1.DocumentCompleted -= handler; });
webBrowser1.Navigate(url);
return taskCompletionSource.Task.GetAwaiter();
}
As you can see I'm at a loss as to how to set the result. Any help would be appreciated with this.
Thanks
TaskAwaiter<PageLoadResult>
, wherePageLoadResult
is a helper struct with two fields: a stringcontent
, and, for example, a return code or result message (which is empty in case of everything went fine)?PageLoadResult
as Doc Brown mentioned, or look into using discriminated unions (which are a more advanced/functional way to solve this problem). Generic types will never be able to help you, since you'd have to declare the type you wanted out before you knew the result. You could usedynamic
, but it's inappropriate in this situation.if (e.Url.Equals(url))
to make your response object