Trying to unit test some simple code for a class project, however every time I try to run the test I get an error that there is no home.exe and no main static main method. However, we haven't gotten to the point where we are supposed to have either of those things yet, so how can I run the test without them?
My code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Home
{
class InventoryType
{
/// <summary>
/// Selects the inventory type and returns the selected value
/// </summary>
public class InventorySelect
{
private string inventoryTypes;
public String InventoryTypes
{
set
{
inventoryTypes = value;
}
get
{
return inventoryTypes;
}
}
/// <summary>
/// Validate that the inventory is returning some sort of value
/// </summary>
/// <returns></returns>
public bool Validate()
{
if (InventoryTypes == null) return false;
return true;
}
}
}
}
My Test Code
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Home.InventoryType.InventorySelect;
namespace HomeTest
{
[TestClass]
public class TestInventoryTypeCase
{
[TestMethod]
public void TestInventoryTypeClass()
{
InventorySelect select = new InventorySelect();
select.inventoryTypes = "Collection";
if (Validate() = true)
Console.WriteLine("Test Passed");
else
if (Validate() = false)
Console.WriteLine("Test Returned False");
else
Console.WriteLine("Test Failed To Run");
Console.ReadLine();
}
}
}
OK, a couple things here.
Make sure that your Output type for your main project (the project to be tested) is ClassLibrary
Use Assertions in your tests
I created a ClassLibrary solution called ExampleLibrary. Created a class called InventoryType and copied in your code e.g.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExampleLibrary
{
class InventoryType
{
/// <summary>
/// Selects the inventory type and returns the selected value
/// </summary>
public class InventorySelect
{
private string inventoryTypes;
public String InventoryTypes
{
set
{
inventoryTypes = value;
}
get
{
return inventoryTypes;
}
}
/// <summary>
/// Validate that the inventory is returning some sort of value
/// </summary>
/// <returns></returns>
public bool Validate()
{
if (InventoryTypes == null) return false;
return true;
}
}
}
}
I then created a Unit Test and coded it as follows:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ExampleLibrary;
namespace HomeTest
{
[TestClass]
public class TestInventoryTypeCase
{
[TestMethod]
public void TestInventoryTypeClass()
{
InventoryType.InventorySelect select = new InventoryType.InventorySelect();
select.InventoryTypes = "Collection";
Assert.IsTrue(select.Validate());
select.InventoryTypes = null;
Assert.IsFalse(select.Validate());
}
}
}
I compile and run the test as described above and it runs and returns Test Passed.
To run a test on the main menu bar at the top of your Visual Studio...
Test - Windows - Test Explorer
In the Test Explorer window, select the test you wish to run and click on the run Icon at the top of the window.
Related
Attempting to implement NavigationView navigation via code-behind using this solution I found:
https://xamlbrewer.wordpress.com/2021/07/06/navigating-in-a-winui-3-desktop-application/
I don't know what I am doing wrong. :-(.
I am new to C#, WinUI. Where is 'App.Navigation'?????
Outline of solution:
All navigation-related code is implemented in a partial class of the Shell window,
encapsulated in an interface that is
exposed via the App instance to
the different XAML pages.
I created an interface: (INavigation.cs)
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MetricReporting.Interfaces
{
interface INavigation
{
NavigationViewItem GetCurrentNavigationViewItem();
List<NavigationViewItem> GetNavigationViewItems();
List<NavigationViewItem> GetNavigationViewItems(Type type);
List<NavigationViewItem> GetNavigationViewItems(Type type, string title);
void SetCurrentNavigationViewItem(NavigationViewItem item);
}
}
I created a partial class of my main window (MainWindow.xaml.Navigation.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MetricReporting
{
public partial class MainWindow : INavigation
{
public NavigationViewItem GetCurrentNavigationViewItem()
{
return NavigationView.SelectedItem as NavigationViewItem;
}
public List<NavigationViewItem> GetNavigationViewItems()
{
var result = new List<NavigationViewItem>();
var items = NavigationView.MenuItems.Select(i => (NavigationViewItem)i).ToList();
items.AddRange(NavigationView.FooterMenuItems.Select(i => (NavigationViewItem)i));
result.AddRange(items);
foreach (NavigationViewItem mainItem in items)
{
result.AddRange(mainItem.MenuItems.Select(i => (NavigationViewItem)i));
}
return result;
}
public List<NavigationViewItem> GetNavigationViewItems(Type type)
{
return GetNavigationViewItems().Where(i => i.Tag.ToString() == type.FullName).ToList();
}
public List<NavigationViewItem> GetNavigationViewItems(Type type, string title)
{
return GetNavigationViewItems(type).Where(ni => ni.Content.ToString() == title).ToList();
}
public void SetCurrentNavigationViewItem(NavigationViewItem item)
{
if (item == null)
{
return;
}
if (item.Tag == null)
{
return;
}
MasterContentFrame.Navigate(
Type.GetType(item.Tag.ToString()),
item.Content);
NavigationView.Header = item.Content;
NavigationView.SelectedItem = item;
}
}
}
I modified the App.xaml.cs:
using MetricReporting.Interfaces;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.UI.Xaml.Shapes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace MetricReporting
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
///
// ** this is what I added per the web article **
public INavigation Navigation => (INavigation)m_window;
//public INavigation Navigation => m_window; Compiler does not like this
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
m_window = new MainWindow();
m_window.Activate();
}
private Window m_window;
}
}
Here is my MainWindow.xaml.cs in case it helps. The NavigationView code works well, I can navigate to all of the pages via navigation menu UI. :-). I just need to be able to navigate from the code behind. I am so sorry for the verbose post.
using MetricReporting.Pages;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Diagnostics;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace MetricReporting
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.Title = "EMB Metric Reporting Tool";
MasterContentFrame.Navigate(typeof(pageHome));
MasterNavigation.Header = "Home";
}
private void MasterNavigation_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
MasterContentFrame.Navigate(typeof(pageSettings));
}
else
{
// find NavigationViewItem with Content that equals InvokedItem
NavigationViewItem item = sender.MenuItems.OfType<NavigationViewItem>().First(x => (string)x.Content == (string)args.InvokedItem);
NavView_Navigate(item);
}
}
private void NavView_Navigate(NavigationViewItem item)
{
switch (item.Tag)
{
case "home":
MasterContentFrame.Navigate(typeof(pageHome));
MasterNavigation.Header = item.Content;
break;
case "datacollection":
MasterContentFrame.Navigate(typeof(pageDataCollection));
MasterNavigation.Header = item.Content;
break;
case "collectdata":
MasterContentFrame.Navigate(typeof(PageCollectMetricData));
MasterNavigation.Header = item.Content;
break;
case "goals":
MasterContentFrame.Navigate(typeof(pageGoals));
MasterNavigation.Header = item.Content;
break;
case "approvals":
MasterContentFrame.Navigate(typeof(pageComments));
MasterNavigation.Header = item.Content;
break;
case "reports":
MasterContentFrame.Navigate(typeof(pageReports));
MasterNavigation.Header = item.Content;
break;
case "admin":
MasterContentFrame.Navigate(typeof(pageAdmin));
MasterNavigation.Header = item.Content;
break;
case "metricstaging":
MasterContentFrame.Navigate(typeof(pageMetricStaging));
MasterNavigation.Header = item.Content;
break;
case "refmetricmain":
MasterContentFrame.Navigate(typeof(pageRefMetricMain));
MasterNavigation.Header = item.Content;
break;
}
}
private async void DisplayCommentDialog()
{
ContentDialog testDialog = new ContentDialog()
{
Title = "Main Window Loaded",
Content = "Main Window Loaded",
CloseButtonText = "Ok"
};
await testDialog.ShowAsync();
}
}
}
The error message tells you that INavigation must be public:
public interface INavigation
{
NavigationViewItem GetCurrentNavigationViewItem();
List<NavigationViewItem> GetNavigationViewItems();
List<NavigationViewItem> GetNavigationViewItems(Type type);
List<NavigationViewItem> GetNavigationViewItems(Type type, string title);
void SetCurrentNavigationViewItem(NavigationViewItem item);
}
If you define it as just interface INavigation { ... } (without the public keyword) it's internal by default and cannot be used as the return type of a public member.
So change interface INavigation to public interface INavigation in your code.
Server start up error when trying to add a purger timer ( game feature) seems that the server is not allowed access?
PurgeTimer:
using System;
using System.Threading;
using System.Collections.Concurrent;
using Plus.HabboHotel.GameClients;
using Plus.HabboHotel.Rooms;
namespace Plus.HabboHotel.Minigames.Purge
{
/// <summary>
/// This will do a countdown before the match starts
/// </summary>
public class PurgeTimer
{
/// <summary>
/// Timer for our operation
/// </summary>
private Timer Timer;
public bool On = false;
/// <summary>
/// Constructor
/// </summary>
public PurgeTimer()
{
// Method to call when completed
TimerCallback TimerCallback = Ticked;
// Create a new instance of timer
Timer = new Timer(TimerCallback, null, 30000, Timeout.Infinite);
}
/// <summary>
/// Method is call when timer is finished
/// </summary>
/// <param name="info">The information</param>
public void Ticked(object info)
{
try
{
if (PurgeManager.Running)
{
foreach (GameClient client in PlusEnvironment.GetGame().GetClientManager()._clients.Values)
{
try
{
if (client == null)
{
continue;
}
client.SendWhisper("[Automatic Event Alert]: The hotel is currently under Purge Mode. All crime is legal.");
}
catch (Exception e)
{
}
}
Timer.Change(30000, Timeout.Infinite);
}
else
{
return;
}
}
catch { }
}
}
}
PurgeManager:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Plus.HabboHotel.Minigames.Purge;
using System.Threading.Tasks;
namespace Plus.HabboHotel.Minigames.Purge
{
public class PurgeManager
{
public static PurgeTimer MainTimer;
public static bool Running;
}
}
Error:
http://prntscr.com/9ss0qb I don't get while it's not accessible!
Firstly, please post the error directly into the question, not as a linked image.
The error Plus.HabboHotel.GameClients.GameClientManager._clients is inaccessible due to its protection level seems pretty clear. From the naming convention used I'd take a guess that the _clients collection is private.
Here is your problem.
From your GameClientManager class, you're trying to access a private field.
private ConcurrentDictionary<int, GameClient> _clients;
For more details regarding your problem, review this. What are Access Modifiers in C#?
I have a specific user control with several properties, including one which is of another class. That class contains a public int[,] this[int x, int y] (I don't remember the exact term for that) as well as a public int[,] property and a private int[,] field. I then have a form containing that control. Whenever I attempt to edit the form and then save, it denies me from saving with the following popup appearing 3 to 6 times in a row:
Note that I don't need the information saved into these arrays in the designer; the value is set to a default each time anyways within the ExampleControl. I don't even have the ability to modify or see these arrays.
Here's all of the code needed to reproduce:
Create a new form application, and then delete the Form1.cs file generated.
Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace ArrayRankIssue
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ExampleForm());
}
}
}
ExampleClass.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ArrayRankIssue
{
public class ExampleClass
{
private int[,] data = new int[2, 2];
public int[,] Data {
get {
return data;
}
set {
if (value.GetLength(0) != data.GetLength(0) || value.GetLength(1) != data.GetLength(1)) {
throw new ArgumentException("Argument must match size of array exactly.");
}
data = value;
}
}
public int[,] this[int x, int y] {
get {
return data;
}
set {
if (value.GetLength(0) != data.GetLength(0) || value.GetLength(1) != data.GetLength(1)) {
throw new ArgumentException("Argument must match size of array exactly.");
}
data = value;
}
}
}
}
ExampleControl.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ArrayRankIssue
{
public partial class ExampleControl : UserControl
{
internal ExampleClass example = new ExampleClass();
public ExampleClass Example {
get {
return example;
}
set {
example = value;
}
}
public ExampleControl() {
InitializeComponent();
}
}
}
ExampleControl.Designer.cs:
namespace ArrayRankIssue
{
partial class ExampleControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
}
#endregion
}
}
ExampleForm.cs:
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;
namespace ArrayRankIssue
{
public partial class ExampleForm : Form
{
public ExampleForm() {
InitializeComponent();
}
}
}
ExampleForm.Designer.cs:
namespace ArrayRankIssue
{
partial class ExampleForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
ArrayRankIssue.ExampleClass exampleClass8 = new ArrayRankIssue.ExampleClass();
this.exampleControl1 = new ArrayRankIssue.ExampleControl();
this.SuspendLayout();
//
// exampleControl1
//
this.exampleControl1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.exampleControl1.Example = exampleClass8;
this.exampleControl1.Location = new System.Drawing.Point(12, 12);
this.exampleControl1.Name = "exampleControl1";
this.exampleControl1.Size = new System.Drawing.Size(150, 150);
this.exampleControl1.TabIndex = 0;
//
// ExampleForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.exampleControl1);
this.Name = "ExampleForm";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private ExampleControl exampleControl1;
}
}
After creating all of these files, select Build-->Rebuild solution [note 1]. Then, double-click ExampleForm.cs, click on the outlined control, and then press left and then right on your keyboard [note 2]. Then, press Control and S, and you will be greeted with the same error message many times.
What I'm looking for is a way to keep this message from popping up (and hopefully to solve the reason why it is popping up, not just suppress it). I have found a simple workaround, which is to close the form designer window and then save, but that seems impractical. Once it is successfully saved, the form appears properly, so there also doesn't seem to be any other effects.
The one other mention of this error message was in this question, but that offered no useful solution.
Note 1: This option is only available in "Expert mode" - if you don't have it, go to Tools-->Settings-->Expert Settings)
Note 2: This is needed so that the file appears as modified by Visual Studio. If it isn't done, you can't force a second save.
Moving these lines worked for me:
From ExampleForm.Designer.cs:
ArrayRankIssue.ExampleClass exampleClass2 = new ArrayRankIssue.ExampleClass();
this.exampleControl1.Example = exampleClass2;
To ExampleForm.cs:
public partial class ExampleForm : Form
{
public ExampleForm()
{
InitializeComponent();
ArrayRankIssue.ExampleClass exampleClass2 = new ArrayRankIssue.ExampleClass();
this.exampleControl1.Example = exampleClass2;
}
}
Solution 2
If you're properties are already setup and you don't need to change them mark them with:
[ReadOnly(true)]
[Browsable(false)]
In your example add those attributes to Data and this in ExampleClass.cs.
You'll have to change your code, remove any existing controls from your form, compile then re-add
In the code below I am attempting to use MEF to match an import to a matching export. The TestMEFClass has an import and an export which share a matching contract name. The export should increment a counter every time it's called.
When I printed the export to the console, it did not increment the counter. Could someone point out my mistake?
Thank you very much,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace MEFConsoleTest {
public class TestMEFClass {
/// <summary>
/// This counter should increment everytime the getter in the ExportString property gets called.
/// </summary>
private int counter = 0;
[Export("Contract_Name")]
public string ExportString {
get {
return "ExportString has been called " + counter++.ToString();
}
}
[Import("Contract_Name")]
public string ImportString { get; set; }
/// <summary>
/// Default Constructor.
/// Make a catalog from this assembly, add it to the container and compose the parts.
/// </summary>
public TestMEFClass() {
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
class Program {
static void Main(string[] args) {
TestMEFClass testClass = new TestMEFClass();
Console.WriteLine(testClass.ImportString);
Console.WriteLine(testClass.ImportString);
Console.ReadLine();
}
}
For reasons I cannot explain at this moment I wasn't able to get MEF and properties imports/exports to work on a mutable property. However, using functions did the trick. I hope this code helps someone else.
Thanks,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace MEFConsoleTest {
public class TestMEFClass {
/// <summary>
/// This counter should increment everytime the getter in the ExportString property gets called.
/// </summary>
private int counter = 0;
[Export("Contract_Name")]
string ExportMethod() {
return ExportString;
}
public string ExportString {
get {
return "ExportString has been called " + counter++.ToString();
}
}
[Import("Contract_Name")]
Func<string> ImportMethod;
public string ImportString { get { return ImportMethod(); } }
/// <summary>
/// Default Constructor.
/// Make a catalog from this assembly, add it to the container and compose the parts.
/// </summary>
public TestMEFClass() {
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
class Program {
static void Main(string[] args) {
TestMEFClass testClass = new TestMEFClass();
for (int x = 0; x < 10; x++) {
Console.WriteLine(testClass.ImportString);
}
Console.ReadLine();
}
}
}
Here is the problem I am trying to model: I have an incoming call center (no outbound calls). There are 3 employee levels - Freshers, Technical Lead, Project Manager. In our call center there is only one TL, one PM and multiple Freshers. Calls that the Freshers cannot handle are escalated to the TL, and calls that the TL cannot handle are escalated to the PM.
I need to take an OO C# approach.
Here is my current attempt: I used C# ConcurrentQueue since I thought it would take care of the 'locks'. I want FIFO for call center. I made a queue for each level.
I have a producer (callers) adding calls to the first queue. Mixed prod/consumer freshers check the call (take or escalate to the next queue). Mixed prod/consumer tl, then a pure consumer project manager.
The output is not what I expect. Only the first fresher runs and the project manager does not run at all. I expect a lot more alternation as the calls are added to the queue.
My code is below. Does anyone have a better approach to this problem or is there something wrong with my code?
The CallCenter Class is where most of the action takes place.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
///
/// MIXED CONSUMER/PRODUCER TYPE
/// </summary>
class Fresher
{
// add a class variable for the number of Employee objects instantiated
private static int fresherNum = 0;
private int fresherId;
private ConcurrentQueue<Call> incommingCalls;
private ConcurrentQueue<Call> outgoingCalls;
public Fresher(ConcurrentQueue<Call> calls, ConcurrentQueue<Call> outcalls)
{
fresherId = ++fresherNum;
incommingCalls = calls;
outgoingCalls = outcalls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return fresherId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null)
{
if (call.EscalationLevel == 0)
{
TakeCalls(call);
}
else
{
TransferCalls(call);
}
}
}
}
/// <summary>
/// Transfer to the TL
/// </summary>
public void TransferCalls(Call call)
{
outgoingCalls.Enqueue(call);
Console.WriteLine(".......Fresher {0} escalated call {1}", ID, call.CallID);
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Fresher {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
/// MIXED CONSUMER/PRODUCER TYPE
/// </summary>
class TechnicalLead
{
// add a class variable for the number of Employee objects instantiated
private static int tlNum = 0;
private int tlId;
private ConcurrentQueue<Call> incommingCalls;
private ConcurrentQueue<Call> outgoingCalls;
public TechnicalLead(ConcurrentQueue<Call> calls, ConcurrentQueue<Call> outcalls)
{
tlId = ++tlNum;
incommingCalls = calls;
outgoingCalls = outcalls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return tlId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null)
{
if (call.EscalationLevel == 1)
{
TakeCalls(call);
}
else
{
TransferCalls(call);
}
}
}
}
/// <summary>
/// Transfer to the PM
/// </summary>
public void TransferCalls(Call call)
{
//Console.WriteLine(".......Technical Lead {0} escalated call {1}", ID, call.CallID);
outgoingCalls.Enqueue(call);
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Technical Lead {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CallCenterThreaded
{
class Call
{
private static int numberCalls = 0;
private int callno;
private int esclataion;
public Call()
{
callno = ++numberCalls;
esclataion = 0;
if(callno % 3 == 0)
{
esclataion = 1;
}
if(callno % 5 == 0)
{
esclataion = 2;
}
}
public int CallID { get { return callno; } }
public int EscalationLevel { get { return esclataion; } }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
///
/// </summary>
class CallCenter
{
private ConcurrentQueue<Call> fresherCalls;
private ConcurrentQueue<Call> tlCalls;
private ConcurrentQueue<Call> pmCalls;
private List<Caller> myCallers;
private List<Fresher> myFreshers;
private TechnicalLead tl;
private ProjectManager pm;
public CallCenter()
{
//initial incomming calls to the fresher queue
fresherCalls = new ConcurrentQueue<Call>();
tlCalls = new ConcurrentQueue<Call>();
pmCalls = new ConcurrentQueue<Call>();
myFreshers = new List<Fresher>();
myCallers = new List<Caller>();
generate_callers();
generate_freshers();
tl = new TechnicalLead(tlCalls, pmCalls);
pm = new ProjectManager(pmCalls);
}
/// <summary>
///
/// </summary>
private void generate_freshers()
{
for (int i = 0; i < 5; i++ )
{
myFreshers.Add(new Fresher(fresherCalls, tlCalls));
}
}
/// <summary>
///
/// </summary>
private void generate_callers()
{
for (int i = 0; i < 5; i++ )
{
myCallers.Add(new Caller(fresherCalls));
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
/// PURE CONSUMER
/// </summary>
class ProjectManager
{
// add a class variable for the number of Employee objects instantiated
private static int pmNum = 0;
private int pmId;
private ConcurrentQueue<Call> incommingCalls;
public ProjectManager(ConcurrentQueue<Call> calls)
{
pmId = ++pmNum;
incommingCalls = calls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return pmId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null && call.EscalationLevel == 2)
{
TakeCalls(call);
}
}
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Project Manager {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
class MainClass
{
static void Main(string[] args)
{
CallCenter myCenter = new CallCenter();
Console.ReadLine();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Threading;
namespace CallCenterThreaded
{
/// <summary>
/// This is a producer. It produces calls and adds them to the queue.
/// PURE PRODUCER TYPE
/// </summary>
class Caller
{
private ConcurrentQueue<Call> incommingCalls;
public Caller(ConcurrentQueue<Call> calls)
{
incommingCalls = calls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(placeCalls));
thread.Start();
}
public void placeCalls()
{
//place 10 calls
for (int callno = 0; callno < 4; callno++)
{
//Console.WriteLine("Call {0} was added to the queue", callno);
incommingCalls.Enqueue(new Call());
}
}
}
}
The problem is in the HandleCalls() methods:
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
…
}
}
What this code does is to check incomingCalls and if there are none, it immediately exits the thread. It's as if the worker came to work, looked at his queue of calls, found nothing there (because he came to work at the same time as the freshers who are supposed to redirect the calls) and so he left and went home.
What you need to do is to wait if there is no work at the moment. Probably the best way to do that is to use BlockingCollection instead of ConcurrentQueue.
Also, your design doesn't seem to that good. For example, there is lots of repeated code.