The Tasks of an Object
A Task as a Type
Introduction
As seen in the previous lesson, a task is created from a class named Task<> (or Task). This means that a task is primarily an (electronic) object. This also means that a Task<> object can be used like any normal class.
Practical Learning: Introducing Tasks Objects
- Start Microsoft Visual Studio and create a Windows Forms application named TrafficTicketsManagement2
- In the Solution Explorer, right-click Form1.cs and click Rename
- Type TicketManagement (to get TicketManagement.cs)
- Press Enter twice to accept the name and display the form
- Design the form as follows:
Control (Name): Text Other Properties GroupBox Speed Ticket Label Speed Limit: TextBox txtSpeedLimit TextAlign: Right Label Driver Speed: TextBox txtDriverSpeed TextAlign: Right Button btnSpeedTicketAmount Ticket Amount TextBox txtSpeedTicketAmount TextAlign: Right GroupBox Police Stop Label Police Stop Reason: ComboBox cbxPoliceStops Items: Other Tail Light Reckless Break Light Under Influence
TextBox txtPoliceTicketAmount TextAlign: Right GroupBox Traffic Light Label Traffic Light Violation: ComboBox cbxTrafficLightViolation Items: Other No Turn on Red High Speed Driving Red Light Drive Through Flashing Light No Stopping
TextBox txtTrafficLightTicketAmount TextAlign: Right - On the form, double-click the Ticket Amount button
- Return to the form and double-click the Police Stop Reason combo box
- Change the document as follows:
using System; using System.Threading.Tasks; using System.Windows.Forms; namespace TrafficTicketsManagement2 { public partial class TicketManagement : Form { public TicketManagement() { InitializeComponent(); } (int limit, int driving) speed; int SetTicketAmountSpeed() { int speedDifference = speed.driving - speed.limit; if (speedDifference < 10) return 0; else if (speedDifference < 20) return 75; else if (speedDifference < 35) return 100; else if (speedDifference < 50) return 150; else return 225; } private void btnSpeedTicketAmount_Click(object sender, EventArgs e) { speed.limit = int.Parse(txtSpeedLimit.Text); speed.driving = int.Parse(txtDriverSpeed.Text); Task<int> ticketSpeed = new Task<int>(SetTicketAmountSpeed); ticketSpeed.Start(); txtSpeedTicketAmount.Text = ticketSpeed.Result.ToString(); } private void cbxPoliceStops_SelectedIndexChanged(object sender, EventArgs e) { Func<int> evaluatePoliceStop = new Func<int>(() => { int amount = 0; switch (cbxPoliceStops.Text) { case "Tail Light": amount = 40; break; case "Break Light": amount = 60; break; case "Reckless": amount = 160; break; case "Under Influence": amount = 300; break; case "Other": amount = 25; break; default: amount = 0; break; } return amount; }); Task<int> processPoliceIssue = Task<int>.Run<int>(evaluatePoliceStop); txtPoliceTicketAmount.Text = processPoliceIssue.Result.ToString(); } } }
- Click the TicketManagement.cs [Design] tab to return to the form
- On the form, double-click the Traffic Light Violation combo box
Returning a Task as Object
A functional task is one that runs asynchronously. One of the most important features here is that the function or method may produce an object that is a task. Of course, you must create the function to produce such an object.
To create a method that produces a task, specify its data type as Task<>. Enter the name of the class as the parameter type. Here is an example:
public Task<double> GetInventory() { }
As always, before the end of the method, make sure you return an object of type Task<>. You have various options. In the function, you can declare a Task<> and initialize it with a constructor that takes a function. You can externally define that other function. Here is an example:
using System;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace GeneralWork
{
public partial class Exercise : Form
{
public Exercise() => InitializeComponent();
string Say()
{
return "Alright! Welcome to my world.";
}
Task<string> GetInventory()
{
Task<string> thought = new Task<string>(Say);
return thought;
}
}
}
Remember that you usually declare a variable only if you are planning to use it. If not, when it comes to a function that returns an object, you can return the instance directly on the return keyword. Here is an example:
using System;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace GeneralWork
{
public partial class Exercise : Form
{
public Exercise() => InitializeComponent();
string Say()
{
return "Alright! Welcome to my world.";
}
Task<string> GetInventory()
{
return new Task<string>(Say);
}
}
}
Remember that if you have a function that involves a single expression, you can reduce its code to an expression-body. Here are examples:
using Sysusing System;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace GeneralWork
{
public partial class Exercise : Form
{
public Exercise() => InitializeComponent();
string Say() => "Alright! Welcome to my world.";
Task<string> GetInventory() => new Task<string>(Say);
}
}
Instead of defining a function externally as we first did, you can define the function as a delegate where it is needed. Here is an example:
using System;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace GeneralWork
{
public partial class Exercise : Form
{
public Exercise() => InitializeComponent();
Task<string> GetInventory()
{
Task<string> thought = new Task<string>(() =>
{
return "Alright! Welcome to my world.";
});
return thought;
}
}
}
After defining the function that returns a Task<> object, you can use its value. To do that, where the object is needed, declare a variable of type Task<> and initialize it. Then use that variable to start the task.
Practical Learning: Returning a Task
- Change the document as follows:
using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace TrafficTicketsManagement2 { public partial class TicketManagement : Form { . . . private void cbxPoliceStops_SelectedIndexChanged(object sender, EventArgs e) { . . . } Task<int> SetTraffiLightTicketAmount() { Task<int> evalluation = new Task<int>(() => { int amount = 0; switch (cbxTrafficLightViolation.Text) { case "Other": amount = 100; break; case "No Turn on Red": amount = 45; break; case "Flashing Light No Stopping": amount = 85; break; case "Red Light Drive Through": amount = 225; break; case "High Speed Driving": amount = 75; break; default: amount = 50; break; } return amount; }); return evalluation; } private void cbxTrafficLightViolation_SelectedIndexChanged(object sender, EventArgs e) { Task<int> light = SetTraffiLightTicketAmount(); light.Start(); txtTrafficLightTicketAmount.Text = light.Result.ToString(); } } }
- Click the TicketManagement.cs [Design] tab to return to the form
A Task as Argument
Because a task is an object based on a class, a task can be passed as argument. To proceed, when creating the function ot method, in its parentheses, type Task<>, include its parameter type, and follow it with a name for the parameter. In the body of the method, ignore the parameter if you don't need it. Otherwise, you can get the value of the parameter. For example, you can initialize it with a value or a method that produces its type of task. Here is an example:
using System;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace GeneralWork
{
public partial class Exercise : Form
{
public Exercise()
{
InitializeComponent();
}
void ProcessPrice(Task<float> cost)
{
}
}
}
You can involve the parameter or its value in any operation or processing you want. You can then use the function or method any way you want outside its body. When calling the function, pass a Task<> object. Here is an example:
using System; using System.Windows.Forms; using System.Threading.Tasks; namespace GeneralWork { public partial class Exercise : Form { public Exercise() { InitializeComponent(); } (int limit, int driving) speed = (35, 75); float SetTicketAmountSpeed() { int speedDifference = speed.driving - speed.limit; if (speedDifference < 10f) return 0; else if (speedDifference < 20f) return 75f; else if (speedDifference < 35f) return 100f; else if (speedDifference < 50f) return 150f; else return 225f; } void ProcessPrice(Task<float> cost) { cost.Start(); MessageBox.Show("Ticket Amount: " + cost.Result.ToString(), "Traffic Tickets Management"); } private void btnTask_Click(object sender, EventArgs e) { Task<float> price = new Task<float>(SetTicketAmountSpeed); ProcessPrice(price); } } }
This would produce:
A Task of an Object Type
Introduction
All the tasks we have created and used so far were producing a primitive type or a string. Indeed, tasks are not limited to value types and strings, a task can produce an object of a class.
A Task that Produces an Object
To make a task produce an object, you first need a class. You have various options. You can first create a class or structure. When creating a task, specify its parameter type as your class or structure. Here is an example:
using System; using System.Windows.Forms; using System.Threading.Tasks; namespace GeneralWork { public partial class Exercise : Form { public Exercise() { InitializeComponent(); } private void btnTask_Click(object sender, EventArgs e) { Task<SpeedTicket> price = ...; } } class SpeedTicket { } }
To initialize a task, you can create a function that returns an object of the class. You can then pass the name of that function to the Task<> constructor. Here is an example:
using System; using System.Windows.Forms; using System.Threading.Tasks; namespace GeneralWork { public partial class Exercise : Form { public Exercise() { InitializeComponent(); } SpeedTicket ProcessInfraction() { return new SpeedTicket() { }; } private void btnTask_Click(object sender, EventArgs e) { Task<SpeedTicket> cost = new Task<SpeedTicket>(ProcessInfraction); } } public class SpeedTicket { } }
After creating and initializing the task, you can start it, by calling the Task.Start()method, excatly as we learned in the previous lesson. To access the values of the object, we saw that you can access the Task.Result property. Because in this case you are dealing with an object (of a class), the Task.Result property actually represents the class. The Intellisense is aware of the public properties of the class and can easily allow you to access each of those properties. Here is an example:
using System; using System.Windows.Forms; using System.Threading.Tasks; namespace GeneralizedWork { public partial class Exercise : Form { public Exercise() { InitializeComponent(); } SpeedTicket ProcessInfraction() { return new SpeedTicket() { Speed = (30, 48), Paid = false }; } private void btnTask_Click(object sender, EventArgs e) { Task<SpeedTicket> cost = new Task<SpeedTicket>(ProcessInfraction); cost.Start(); MessageBox.Show("Ticket Summary: " + cost.Result.Summary, "Traffic Tickets Management"); } } public class SpeedTicket { public (int limit, int driving) Speed { get; set; } public bool Paid { get; set; } public float SpeedDifference => Speed.driving - Speed.limit; public float Amount { get { if (SpeedDifference < 10) return 0; else if (SpeedDifference < 20) return 75; else if (SpeedDifference < 35) return 100; else if (SpeedDifference < 50) return 150; else return 225; } } public string Summary { get { string msg = "The infraction has not yet been paid."; if (Paid == true) msg = "The ticket has already been paid."; return $"The speed on the road is {Speed.limit} mph. " + $"The vehicle was driven at {Speed.driving} mph, " + $"which is a difference of {SpeedDifference} mph. " + $"Consequently, the driver was issued a ticket for ${Amount}." + Environment.NewLine + Environment.NewLine + msg; } } } }
This would produce:
In the above example, we used our own class for the task. As we know already, the .NET Framework provides a rich collection of classes and structures. If one of those classes fulfills your needs, you can use it. Simply follow the same steps as above: Create a function that returns an object of the class, create and initialize a Task<> object, start the task, and finally access the Task<>.Result property of that task. Remember that the Task<>.Result property gives you access to the public property of the class on which the task is performed. Here is an example:
using System; using System.Windows.Forms; using System.Threading.Tasks; namespace GeneralWork { public partial class Exercise : Form { public Exercise() { InitializeComponent(); } Form CreateDialogBox() { Form frm = new Form(); frm.FormBorderStyle = FormBorderStyle.FixedDialog; frm.MaximizeBox = false; frm.MinimizeBox = false; frm.StartPosition = FormStartPosition.CenterScreen; frm.Size = new System.Drawing.Size(620, 340); frm.Text = "Traffic Tickets Management"; return frm; } private void btnTask_Click(object sender, EventArgs e) { Task<Form> dlgBox = new Task<Form>(CreateDialogBox); dlgBox.Start(); dlgBox.Result.ShowDialog(); } } }
This would produce:
In the above examples of tasks that produce an object, we created a function that produced the desired object. As an alternative and as we saw in the previous lesson, you can either nest the function where it will be needed or you can create it as a delegate or a lambda expression. Here is an example:
using System;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace GeneralWork
{
public partial class Exercise : Form
{
public Exercise()
{
InitializeComponent();
}
private void btnTask_Click(object sender, EventArgs e)
{
Task<Form> dlgBox = new Task<Form>(() =>
{
Form frm = new Form();
frm.FormBorderStyle = FormBorderStyle.FixedDialog;
frm.MaximizeBox = false;
frm.MinimizeBox = false;
frm.StartPosition = FormStartPosition.CenterScreen;
frm.Size = new System.Drawing.Size(620, 340);
frm.Text = "Traffic Tickets Management";
return frm;
});
dlgBox.Start();
dlgBox.Result.ShowDialog();
}
}
}
In the above two examples, we used regular classes. Indeed, you can use an abstract class, a sealed class, or a structure. In fact, you can use an interface. In this case, specify the parameter type as the interface. Here is an example:
interface ITrafficTicket { } class Exercise : Form { void Specify() { Task<ITrafficTicket> applied = new Task<ITrafficTicket>(...); } }
If you create a function or method that returns an interface, of course, make sure it returns a valid object. As you should know already, in the function or method, you can create an object using a class that implements the interface. Here is an example:
using System; using System.Windows.Forms; using System.Threading.Tasks; public Exercise { ITrafficTicket CreateTicket() { ITrafficTicket law = new PoliceStop(); return law; } void MakeItHappen() { Task<ITrafficTicket> applied = new Task<ITrafficTicket>(CreateTicket); } } interface ITrafficTicket { } // A class that implements the interface class PoliceStop : ITrafficTicket { }
Other than that, you can start the task and get its result, which would give you access to the properties of the interface. Here is an example:
using System; using System.Windows.Forms; using System.Threading.Tasks; namespace GeneralWork { public partial class Exercise : Form { public Exercise() { InitializeComponent(); } ITrafficTicket CreateTicket() { double pay = 85; bool done = false; ITrafficTicket law = new PoliceStop(pay, done); return law; } private void btnTask_Click(object sender, EventArgs e) { Task<ITrafficTicket> applied = new Task<ITrafficTicket>(CreateTicket); applied.Start(); MessageBox.Show("Ticket Summary: " + applied.Result.Summary, "Traffic Tickets Management"); } } public interface ITrafficTicket { double Amount { get; } string Summary { get; } bool Paid { get; set; } } public class PoliceStop : ITrafficTicket { public PoliceStop(double amount, bool status) { Amount = amount; Paid = status; } public double Amount { get; } public bool Paid { get; set; } public string Summary { get { string msg = "The infraction has not yet been paid."; if (Paid == true) msg = "The ticket has already been paid."; return "The vehicle was stopped because it kept moving on the road " + "shoulder. The driver didn't seem to be in control. Upon " + "arrest, the driver was incoherent to every question asked." + Environment.NewLine + Environment.NewLine + $"A ticket in the amount of ${Amount} was issued to the driver." + Environment.NewLine + Environment.NewLine + msg; ; } } } }
This would produce:
Passing a Task as Argument
As you may know by now, a task is an object created from the Task<> class. This makes it possible for you to create a function or method that uses an object of the Task<> class as argument. In the body of the function, you can ignore or use the argument. When calling the function, make sure you pass an argument that is a Task<> type. Here is an example:
using System;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace GeneralWork
{
public partial class Exercise : Form
{
public Exercise()
{
InitializeComponent();
}
SpeedTicket ProcessInfraction()
{
return new SpeedTicket()
{
Speed = (55, 82),
Paid = false
};
}
void Provide(Task<SpeedTicket> impress)
{
impress.Start();
MessageBox.Show("Ticket Summary: " + impress.Result.Summary, "Traffic Tickets Management");
}
private void btnTask_Click(object sender, EventArgs e)
{
Task<SpeedTicket> cost = new Task<SpeedTicket>(ProcessInfraction);
Provide(cost);
}
}
public class SpeedTicket
{
public (int limit, int driving) Speed { get; set; }
public bool Paid { get; set; }
public float SpeedDifference => Speed.driving - Speed.limit;
public float Amount
{
get
{
if (SpeedDifference < 10)
return 0;
else if (SpeedDifference < 20)
return 75;
else if (SpeedDifference < 35)
return 100;
else if (SpeedDifference < 50)
return 150;
else
return 225;
}
}
public string Summary
{
get
{
string msg = "The infraction has not yet been paid.";
if (Paid == true)
msg = "The ticket has already been paid.";
return $"The speed on the road is {Speed.limit} mph. " +
$"The vehicle was driven at {Speed.driving} mph, " +
$"which is a difference of {SpeedDifference} mph. " +
$"Consequently, the driver was issued a ticket for ${Amount}."
+ Environment.NewLine + Environment.NewLine + msg;
}
}
}
}
This would produce:
In the above example, we used a Task<> object that produces an object of a class type. In the same way, you can pass a Task<>that acts on an interface.
Returning an Objective Task
You can create a function or method that returns a task. Once again, you can make the task produce an object. You can use your own class. When creating the function, specify its return type as Task<> with a class as the parameter type. In the body of the function, make sure it returns an appropriate task. When calling the function, you can assign the call to a Task<> object. Here is an example:
using System;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace GeneralizedWork
{
public partial class Exercise : Form
{
public Exercise()
{
InitializeComponent();
}
SpeedTicket ProcessInfraction()
{
return new SpeedTicket()
{
Speed = (35, 76),
Paid = false
};
}
void Provide(Task<SpeedTicket> impress)
{
impress.Start();
MessageBox.Show("Ticket Summary: " + impress.Result.Summary, "Traffic Tickets Management");
}
Task<SpeedTicket> Produce()
{
Task<SpeedTicket> done = new Task<SpeedTicket>(ProcessInfraction);
return done;
}
private void btnTask_Click(object sender, EventArgs e)
{
Task<SpeedTicket> cost = Produce();
Provide(cost);
}
}
public class SpeedTicket
{
public (int limit, int driving) Speed { get; set; }
public bool Paid { get; set; }
public float SpeedDifference => Speed.driving - Speed.limit;
public float Amount
{
get
{
if (SpeedDifference < 10)
return 0;
else if (SpeedDifference < 20)
return 75;
else if (SpeedDifference < 35)
return 100;
else if (SpeedDifference < 50)
return 150;
else
return 225;
}
}
public string Summary
{
get
{
string msg = "The infraction has not yet been paid.";
if (Paid == true)
msg = "The ticket has already been paid.";
return $"The speed on the road is {Speed.limit} mph. " +
$"The vehicle was driven at {Speed.driving} mph, " +
$"which is a difference of {SpeedDifference} mph. " +
$"Consequently, the driver was issued a ticket for ${Amount}."
+ Environment.NewLine + Environment.NewLine + msg; }
}
}
}
This would produce:
Returning an Interfaced Task
As done for a regular class, you can create a function or method that returns a task that produces an interface. Of course, the parameter type of the Task<> must be an interface. Otherwise, the step is primarily the same as those of a class as seen above. Here is an example:
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TrafficTicketsManagement
{
public partial class TicketManagement : Form
{
public TicketManagement()
{
InitializeComponent();
}
ITrafficTicket CreateTicket()
{
double pay = 125;
bool done = true;
ITrafficTicket law = new PoliceStop(pay, done);
return law;
}
Task<ITrafficTicket> Adjust()
{
return new Task<ITrafficTicket>(CreateTicket);
}
private void btnTask_Click(object sender, EventArgs e)
{
Task<ITrafficTicket> applied = Adjust();
applied.Start();
MessageBox.Show("Ticket Summary: " + applied.Result.Summary, "Traffic Tickets Management");
}
}
public interface ITrafficTicket
{
double Amount { get; }
string Summary { get; }
bool Paid { get; set; }
}
public class PoliceStop : ITrafficTicket
{
public PoliceStop(double amount, bool status)
{
Amount = amount;
Paid = status;
}
public double Amount { get; }
public bool Paid { get; set; }
public string Summary
{
get
{
string msg = "The infraction has not yet been paid.";
if (Paid == true)
msg = "The ticket has already been paid.";
return "The vehicle was stopped because it kept moving on the road " +
"shoulder. The driver didn't seem to be in control. Upon " +
"arrest, the driver was incoherent to every question asked." +
Environment.NewLine + Environment.NewLine +
$"A ticket in the amount of ${Amount} was issued to the driver."
+ Environment.NewLine + Environment.NewLine + msg;
;
}
}
}
}
This would produce:
Practical Learning: Ending the Lesson
- Close your programming environment
|
||
Previous | Copyright © 2014-2021, FunctionX | Next |
|