I need to make a simple program that asks you to press a button twice, once to start the timer and second time to stop it, then it has to show you the difference in seconds from the moment you pressed these buttons, yet I can't figure out a way to write the code in Main. I think my class Stoper is made properly, but I am not really sure.
I've tried different ways to use ReadKey to assign the starting DateTime to a variable.
class Stoper
{
DateTime czas_zakonczenia;
DateTime czas;
DateTime czas_rozpoczecia;
private DateTime Czas_rozpoczecia
{
get
{
return Czas_rozpoczecia;
}
}
public DateTime Start(DateTime czas_rozpoczecia)
{
return czas_rozpoczecia = DateTime.Now;
}
public DateTime Stop(DateTime czas_zakonczenia)
{
return czas_zakonczenia = DateTime.Now;
}
public void WyswietlCzas()
{
var czas = (Start(czas_rozpoczecia) - Stop(czas_zakonczenia)).TotalSeconds;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Kliknij dowolony przycisk gdy chcesz zaczac pomiar czasu.");
Stoper s1 = new Stoper(Start());
}
}
You don't need a custom class for that. You can use the StopWatch class. Try something like this:
static void Main(string[] args)
{
Console.WriteLine("Press any key to start the timer");
Console.ReadKey();
Stopwatch sw = Stopwatch.StartNew();
Console.WriteLine("Timer started. Press any key to stop");
Console.ReadKey();
sw.Stop();
Console.WriteLine("The timer has stopped.");
Console.WriteLine($"Elapsed time is: {sw.Elapsed.TotalSeconds} seconds.");
Console.ReadLine();
}
If you have to use a custom class. There are some irrelevant variables in your class and the logic is also incorrect. You may rewrite your class into something like this: (feel free to translate the variables/method names into your language)
class Stoper
{
public TimeSpan ElapsedTime { get; set; }
private DateTime startDate;
public void Start()
{
startDate = DateTime.Now;
}
public void Stop()
{
ElapsedTime = DateTime.Now - startDate;
}
}
Then, you can use it in the same way the StopWatch class is used above:
static void Main(string[] args)
{
Console.WriteLine("Press any key to start the timer");
Console.ReadKey();
Stoper s1 = new Stoper();
s1.Start();
Console.WriteLine("Timer started. Press any key to stop");
Console.ReadKey();
s1.Stop();
Console.WriteLine("The timer has stopped.");
Console.WriteLine($"Elapsed time is: {s1.ElapsedTime.TotalSeconds} seconds.");
Console.ReadLine();
}
Use the Stopwatch class:
private static void Main()
{
Stopwatch stopWatch = new Stopwatch();
Console.WriteLine("Press any key to start the timer.\n");
Console.ReadKey();
stopWatch.Start();
Console.WriteLine("Press any key to stop the timer.\n");
Console.ReadKey();
stopWatch.Stop();
Console.WriteLine($"Elapsed seconds: {stopWatch.Elapsed.TotalSeconds}");
Console.ReadKey();
}
private static void Main(string[] args)
{
Console.WriteLine("Press any key to Start Timer");
Console.ReadKey();
Console.WriteLine("\nTimer Started");
var startTime = DateTime.Now;
Console.WriteLine("Press any key to Stop Timer");
Console.ReadKey();
var stopTime = DateTime.Now;
var sb = "\n" + (stopTime - startTime);
Console.WriteLine(sb);
}
There are several problems in your code:
This causes a stack overflow. Because you use the property (with the capital C), where you want to use the field (with the small c). C# is case sensitive.
private DateTime Czas_rozpoczecia
{
get
{
return Czas_rozpoczecia;
}
}
You probably want this:
private DateTime Czas_rozpoczecia
{
get
{
return czas_rozpoczecia;
// ^ Small letter
}
}
Or even this:
private DateTime Czas_rozpoczecia => czas_rozpoczecia;
You use an argument with the same name as the field? Then you assign a value (to the argument?) and forget about it.
public DateTime Start(DateTime czas_rozpoczecia)
{
return czas_rozpoczecia = DateTime.Now;
}
You probably want to use it like this. Store the current DateTime in the field. And you should fix this for the Stop method as well.
public DateTime Start()
{
czas_rozpoczecia = DateTime.Now;
}
The difference between two DateTimes is a TimeSpan, and there's no use to store it, since you have all fields already.
public Double WyswietlCzas()
{
return (czas_rozpoczecia - czas_zakonczenia).TotalSeconds;
}
}
Now fix the main code. Use ReadKey to wait for a key. And call the methods using the instance (s1) you just created.
var s1 = new Stoper();
Console.ReadKey();
s1.Start();
Console.ReadKey();
s2.Stop();
And you should be able to figure out how to print the seconds yourself.
Related
I'm trying to write a program that consists of some items (only 2 of them for now). It doesn't show any errors in the console, but when I try to call the Main function more than once, it doesn't execute the loops inside. Here's the code by the way.
public static class Program
{
public static string input = Convert.ToString(Console.ReadLine());
public static int health = 100;
public static int energy = 100;
public static void Main()
{
Console.WriteLine("This is a game used for testing items");
Console.WriteLine("Would you like to use items or get them? (Typing in status shows the value of your health and energy)");
if (Program.input == "get")
{
Items.GetItems();
}
if (Program.input == "use")
{
ItemUser();
}
if (Program.input == "status")
{
StatusChecker();
}
}
public static void StatusChecker()
{
Console.WriteLine("Your health is " + Program.health);
Console.WriteLine("Your energy is " + Program.energy);
}
public static void ItemUser()
{
Console.WriteLine("What do you want to use?");
string useChecker = Convert.ToString(Console.ReadLine());
if (useChecker == "healthPotion")
{
health += 100;
Items.healthPotion--;
}
if (useChecker == "energyDrink")
{
energy += 100;
Items.energyDrink--;
}
}
}
public static class Items
{
public static int healthPotion = 0;
public static int energyDrink = 0;
public static void GetItems()
{
Console.WriteLine();
string itemChecker = Convert.ToString(Console.ReadLine());
if ( itemChecker == "health potion")
{
healthPotion++;
Program.Main();
}
if (itemChecker == "energy drink")
{
energyDrink++;
Program.Main();
}
}
So I wanted the program to get the values after updating them, but it just stops after I call Main method more than once. Can anyone help me?
(I'm not that great at coding so I couldn't make really efficient code)
You don't have any loops inside your Main method and every time you run the application you start from scratch and each of your variables contain initial values. If I get right what you're trying to achieve, I would suggest you to write the Main method like this to have loop which will ask a user for a command until the user enters "quit":
static void Main(string[] args)
{
Console.WriteLine("This is a game used for testing items");
while (true)
{
Console.WriteLine("Would you like to use items or get them? (Typing in status shows the value of your health and energy)");
string userAnswer = Console.ReadLine();
if (userAnswer == "quit") break;
if (userAnswer == "get")
{
Items.GetItems();
}
if (userAnswer == "use")
{
ItemUser();
}
if (userAnswer == "status")
{
StatusChecker();
}
}
}
I noticed also that when you call ItemUser method you update static variables of your Items class, but in the StatusChecker method you write to the console variables of your Program class. They are actually different, so I think in your StatusChecker method you may want do the following:
public static void StatusChecker()
{
Console.WriteLine("Your health is " + Items.health);
Console.WriteLine("Your energy is " + Items.energy);
}
You are assigning a variable here:
public static string input = Convert.ToString(Console.ReadLine());
So the next time you call your "Main" method it will use the value you typed in the first time your app executed. If you want it to ask each time you'll need to do something like this:
public static void Main()
{
input = Convert.ToString(Console.ReadLine());
...
}
Another thing is that it can exit after the first call if you type in i.e. "status".
Issue number 3 is that this is not the "nice" way to write a program. The Main method is supposed to be executed when your app starts as it is the entry point (more on that here).
This question already has answers here:
Calculate the execution time of a method
(8 answers)
Closed 3 years ago.
I am trying to test that calling SendMessage after a set amount of time (in my case 1300ms) will give the correct result in the event handler. However Thread.Sleep(1300) is not waiting 1300ms, it only waits for about 300ms.
Unit Test
using System;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using mvce;
namespace mvceTest
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Class1 c = new Class1();
string finalResult = "";
c.AnEvent += (o, entry) => { finalResult = entry; };
DateTime start = DateTime.Now;
while (finalResult == "")
{
Thread.Sleep(1300);
c.SendMessage("message");
}
DateTime end = DateTime.Now;
Assert.AreEqual(1300, (end - start).Milliseconds);
Assert.AreEqual("message", finalResult);
}
}
}
Class1
using System;
namespace mvce
{
public class Class1
{
private readonly object _lock = new object();
private event EventHandler<string> _anEvent;
public event EventHandler<string> AnEvent
{
add
{
lock (_lock)
{
_anEvent += value;
}
}
remove
{
lock (_lock)
{
_anEvent -= value;
}
}
}
public void SendMessage(string message)
{
_anEvent?.Invoke(this, message);
}
}
}
The output I get is
Assert.AreEqual failed. Expected:<1300>. Actual:<302>.
Obviously I don't expect them to be equal, this is just for the example.
I have also tried System.Threading.Tasks.Task.Delay(1300).Wait();, but I get the same result.
How can I get the test thread to wait the right amount of time? Why doesn't Thread.Sleep work?
In your assert you're using:
Assert.AreEqual(1300, (end - start).Milliseconds);
Try using the following instead:
Assert.AreEqual(1300, (end - start).TotalMilliseconds);
TimeSpan.TotalMilliseconds :
Gets the value of the current TimeSpan structure expressed in whole
and fractional milliseconds.
TimeSpan.Milliseconds :
Gets the milliseconds component of the time interval represented by
the current TimeSpan structure.
The reason it is returning 300ms is because milliseconds component of your TimeSpan is in fact 300 milliseconds, but also the seconds component of your TimeSpan is 1 second.
You should use TotalMilliseconds instead of Milliseconds.
Also, it's better to measure time using Stopwatch.
This code shows that thread is indeed sleeping for 1300ms:
static void Main(string[] args)
{
Class1 c = new Class1();
string finalResult = "";
c.AnEvent += (o, entry) => { finalResult = entry; };
Stopwatch sw = new Stopwatch();
DateTime start = DateTime.Now;
while (finalResult == "")
{
sw.Start();
Thread.Sleep(1300);
var ms = sw.ElapsedMilliseconds;
Console.WriteLine(ms);
c.SendMessage("message");
}
DateTime end = DateTime.Now;
Console.WriteLine((end - start).TotalMilliseconds);
}
I've created a stop watch app. Within its constructor I've started a new thread that has a while(true) loop to check for keyboard hits - if Space is hit the stopwatch will pause; if A is hit, the stopwatch resumes. This works once for each, however after that it does not register, and it seems the loop is no longer running or something because I put a log inside the while loop (but outside of the if statements) and it does not get printed every loop as I presumed it would. (Note I had to include hasPressedSpace and hasPressedA booleans because the Input events were being registered multiple times during one keystroke).
namespace StopWatch
{
class Program
{
static void Main(string[] args)
{
StopWatch stopWatch = new StopWatch();
stopWatch.Start();
}
}
public class StopWatch
{
public TimeSpan Duration { get; private set; }
private bool _hasStoppped;
private ThreadStart threadStart;
private Thread thread;
private bool isPaused;
public StopWatch()
{
Duration = new TimeSpan();
threadStart = new ThreadStart(KeyBoardThread);
thread = new Thread(threadStart);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
public void Start()
{
while (!_hasStoppped)
{
Thread.Sleep(100);
Duration += TimeSpan.FromMilliseconds(100);
Console.WriteLine("Duration: " + Duration);
}
}
void KeyBoardThread()
{
bool hasPressedSpace = false;
bool hasPressedA = false;
while (true)
{
if (Keyboard.IsKeyDown(Key.Space) && !hasPressedSpace)
{
hasPressedSpace = true;
hasPressedA = false;
Stop();
}
if (Keyboard.IsKeyDown(Key.A) && !hasPressedA)
{
hasPressedSpace = false;
hasPressedA = true;
_hasStoppped = false;
Start();
}
}
}
void Stop()
{
Console.WriteLine("stop called");
_hasStoppped = true;
}
}
}
Add the following line to the end of your main function:
Console.WriteLine("Exit");
You will observe that after pressing the Space key, the program prints "Exit". Then it, well, exits!
The problem is here:
while (!_hasStoppped)
{
Thread.Sleep(100);
Duration += TimeSpan.FromMilliseconds(100);
Console.WriteLine("Duration: " + Duration);
}
If _hasStoppped is true the thread completes and so does your program. You need to rethink your logic.
You may also like to note that a Stopwatch class is built into the .NET Framework :)
I have a maze game and I'm trying to create two Timers at a time.
1st (Exits the game after 300 secs)
t1.Interval = 30000;
t1.Enabled = true;
t1.Elapsed += new ElapsedEventHandler(hiddenTimer);
public static void hiddenTimer(object source, ElapsedEventArgs e)
{
Console.Clear();
Environment.Exit(1);
}
2nd (Displays the time remaining every 1 sec (like a real timer))
t2.Interval = 1000;
t2.Enabled = true;
t2.Elapsed += new ElapsedEventHandler(showTimer);
public static void showTimer(object source, ElapsedEventArgs e)
{
Console.Write(timeLeft);
}
I would want to pass declare timeLeft globally but it says that "An object reference is required for the non-static field, method, or property..."
How would I declare it properly?
By making a static property:
public static Double TimeLeft { get; set; }
This is if you want to Publicliy accessable from your entire context, if you want it private, just change public to private.
Just a side note, the built in Timer doesn't support polling for the remaining time until the next elapse. Either you decrease TimeLeft in each Elapse-event on the 1sec timer or you can have a look at this.
Edit
Here is one way to do it with one timer, first I declare two properties and one constant field that I use, don't bother that they are static, it's just easier to run it as a console application this way.
public static Timer SystemTimer { get; set; }
public static double Elapsed { get; set; }
private const double CycleInterval = 1000;
Then in my Main-method I have the following to initiate my Timer
SystemTimer = new Timer();
SystemTimer.Interval = CycleInterval;
SystemTimer.Enabled = true;
SystemTimer.Elapsed += Cycle;
SystemTimer.Start();
Having this, the Cycle-event handler can look like this:
static void Cycle(object sender, ElapsedEventArgs e)
{
Elapsed += CycleInterval;
if ((Elapsed%5000) == 0.0)
{
Console.WriteLine("5 sec elapsed!");
// Do stuff each 5 sec
}
if ((Elapsed % 10000) == 0.0)
{
Console.WriteLine("10 sec elapsed!");
// Do stuff each 10 sec
}
Console.WriteLine("Elapsed: {0}", Elapsed);
}
You could also have Elapsed being a TimeSpan, but you can refactor this as you like.
Here's my complete source code that I used:
using System;
using System.IO;
using System.Timers;
namespace ConsoleApplication5
{
class Program
{
public static Timer SystemTimer { get; set; }
public static double Elapsed { get; set; }
private const double CycleInterval = 1000;
static void Main(string[] args)
{
SystemTimer = new Timer();
SystemTimer.Interval = CycleInterval;
SystemTimer.Enabled = true;
SystemTimer.Elapsed += Cycle;
SystemTimer.Start();
while (true) ;
}
static void Cycle(object sender, ElapsedEventArgs e)
{
Elapsed += CycleInterval;
if ((Elapsed%5000) == 0.0)
{
Console.WriteLine("5 sec elapsed!");
// Do stuff each 5 sec
}
if ((Elapsed % 10000) == 0.0)
{
Console.WriteLine("10 sec elapsed!");
// Do stuff each 10 sec
}
Console.WriteLine("Elapsed: {0}", Elapsed);
}
}
}
And this is what it looks like when I run it:
First of all, you should declare your timeLeft as a static if you want it to behave like a global variable.
Secondly I'd use one timer and keep track of the time separately for each event:
static DateTime startTime = DateTime.Now;
static DateTime lastTime = DateTime.Now;
In your timer, which should be set to something to give more accuracy like 1/10 of a second, do this:
if (DateTime.Now - lastTime > new TimeSpan(0, 0, 1))
// Update the time here for your 1s clock
lastTime = DateTime.Now;
if (DateTime.Now - startTime > new TimeSpan(0, 0, 300))
// Exit the game
Your timings will be more accurate this way.
Mark it static:
public static int TimeLeft;
Your timeLeft memeber is not static.
Make it static or make showTimer method non static.
Regards.
I'm not really writing an alarm clock application, but it will help to illustrate my question.
Let's say that I have a method in my application, and I want this method to be called every hour on the hour (e.g. at 7:00 PM, 8:00 PM, 9:00 PM etc.). I could create a Timer and set its Interval to 3600000, but eventually this would drift out of sync with the system clock. Or I could use a while() loop with Thread.Sleep(n) to periodically check the system time and call the method when the desired time is reached, but I don't like this either (Thread.Sleep(n) is a big code smell for me).
What I'm looking for is some method in .Net that lets me pass in a future DateTime object and a method delegate or event handler, but I haven't been able to find any such thing. I suspect there's a method in the Win32 API that does this, but I haven't been able to find that, either.
Or, you could create a timer with an interval of 1 second and check the current time every second until the event time is reached, if so, you raise your event.
You can make a simple wrapper for that :
public class AlarmClock
{
public AlarmClock(DateTime alarmTime)
{
this.alarmTime = alarmTime;
timer = new Timer();
timer.Elapsed += timer_Elapsed;
timer.Interval = 1000;
timer.Start();
enabled = true;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if(enabled && DateTime.Now > alarmTime)
{
enabled = false;
OnAlarm();
timer.Stop();
}
}
protected virtual void OnAlarm()
{
if(alarmEvent != null)
alarmEvent(this, EventArgs.Empty);
}
public event EventHandler Alarm
{
add { alarmEvent += value; }
remove { alarmEvent -= value; }
}
private EventHandler alarmEvent;
private Timer timer;
private DateTime alarmTime;
private bool enabled;
}
Usage:
AlarmClock clock = new AlarmClock(someFutureTime);
clock.Alarm += (sender, e) => MessageBox.Show("Wake up!");
Please note the code above is very sketchy and not thread safe.
Interesting, I've actually come across a very similar issue and went looking for a method in the .Net framework that would handle this scenario. In the end, we ended up implementing our own solution that was a variation on a while loop w/ Thread.Sleep(n) where n gets smaller the closer you get to the desired target time (logarithmically actually, but with some reasonable thresholds so you're not maxing the cpu when you get close to the target time.) Here's a really simple implementation that just sleeps half the time between now and the target time.
class Program
{
static void Main(string[] args)
{
SleepToTarget Temp = new SleepToTarget(DateTime.Now.AddSeconds(30),Done);
Temp.Start();
Console.ReadLine();
}
static void Done()
{
Console.WriteLine("Done");
}
}
class SleepToTarget
{
private DateTime TargetTime;
private Action MyAction;
private const int MinSleepMilliseconds = 250;
public SleepToTarget(DateTime TargetTime,Action MyAction)
{
this.TargetTime = TargetTime;
this.MyAction = MyAction;
}
public void Start()
{
new Thread(new ThreadStart(ProcessTimer)).Start();
}
private void ProcessTimer()
{
DateTime Now = DateTime.Now;
while (Now < TargetTime)
{
int SleepMilliseconds = (int) Math.Round((TargetTime - Now).TotalMilliseconds / 2);
Console.WriteLine(SleepMilliseconds);
Thread.Sleep(SleepMilliseconds > MinSleepMilliseconds ? SleepMilliseconds : MinSleepMilliseconds);
Now = DateTime.Now;
}
MyAction();
}
}
You could simply reset the timer duration each time it fires, like this:
// using System.Timers;
private void myMethod()
{
var timer = new Timer {
AutoReset = false, Interval = getMillisecondsToNextAlarm() };
timer.Elapsed += (src, args) =>
{
// Do timer handling here.
timer.Interval = getMillisecondsToNextAlarm();
timer.Start();
};
timer.Start();
}
private double getMillisecondsToNextAlarm()
{
// This is an example of making the alarm go off at every "o'clock"
var now = DateTime.Now;
var inOneHour = now.AddHours(1.0);
var roundedNextHour = new DateTime(
inOneHour.Year, inOneHour.Month, inOneHour.Day, inOneHour.Hour, 0, 0);
return (roundedNextHour - now).TotalMilliseconds;
}
You could create an Alarm class which has a dedicated thread which goes to sleep until the specified time, but this will use the Thread.Sleep method. Something like:
/// <summary>
/// Alarm Class
/// </summary>
public class Alarm
{
private TimeSpan wakeupTime;
public Alarm(TimeSpan WakeUpTime)
{
this.wakeupTime = WakeUpTime;
System.Threading.Thread t = new System.Threading.Thread(TimerThread) { IsBackground = true, Name = "Alarm" };
t.Start();
}
/// <summary>
/// Alarm Event
/// </summary>
public event EventHandler AlarmEvent = delegate { };
private void TimerThread()
{
DateTime nextWakeUp = DateTime.Today + wakeupTime;
if (nextWakeUp < DateTime.Now) nextWakeUp = nextWakeUp.AddDays(1.0);
while (true)
{
TimeSpan ts = nextWakeUp.Subtract(DateTime.Now);
System.Threading.Thread.Sleep((int)ts.TotalMilliseconds);
try { AlarmEvent(this, EventArgs.Empty); }
catch { }
nextWakeUp = nextWakeUp.AddDays(1.0);
}
}
}
I know it's a bit of an old question, but I came across this when I was looking for an answer to something else. I thought I'd throw my two cents in here, since I recently had this particular issue.
Another thing you can do is schedule the method like so:
/// Schedule the given action for the given time.
public async void ScheduleAction ( Action action , DateTime ExecutionTime )
{
try
{
await Task.Delay ( ( int ) ExecutionTime.Subtract ( DateTime.Now ).TotalMilliseconds );
action ( );
}
catch ( Exception )
{
// Something went wrong
}
}
Bearing in mind it can only wait up to the maximum value of int 32 (somewhere around a month), it should work for your purposes. Usage:
void MethodToRun ( )
{
Console.WriteLine ("Hello, World!");
}
void CallingMethod ( )
{
var NextRunTime = DateTime.Now.AddHours(1);
ScheduleAction ( MethodToRun, NextRunTime );
}
And you should have a console message in an hour.
What about System.Timers.Timer class ? See http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
I have used this before with great success:
Vb.net:
Imports System.Threading
Public Class AlarmClock
Public startTime As Integer = TimeOfDay.Hour
Public interval As Integer = 1
Public Event SoundAlarm()
Public Sub CheckTime()
While TimeOfDay.Hour < startTime + interval
Application.DoEvents()
End While
RaiseEvent SoundAlarm()
End Sub
Public Sub StartClock()
Dim clockthread As Thread = New Thread(AddressOf CheckTime)
clockthread.Start()
End Sub
End Class
C#:
using System.Threading;
public class AlarmClock
{
public int startTime = TimeOfDay.Hour;
public int interval = 1;
public event SoundAlarmEventHandler SoundAlarm;
public delegate void SoundAlarmEventHandler();
public void CheckTime()
{
while (TimeOfDay.Hour < startTime + interval) {
Application.DoEvents();
}
if (SoundAlarm != null) {
SoundAlarm();
}
}
public void StartClock()
{
Thread clockthread = new Thread(CheckTime);
clockthread.Start();
}
}
I don't know if the c# works, but the vb works just fine.
Usage in VB:
Dim clock As New AlarmClock
clock.interval = 1 'Interval is in hours, could easily convert to anything else
clock.StartClock()
Then, just add an event handler for the SoundAlarm event.