Reactive Extension Simple Example not Working with Number Generator - c#

Trying to setup Reactive Extension for a simple example. Eg: there is random Number Generator, and anytime Number Divisible by three is spotted, "Write Hello" and Observe the Event. However it does not seem to be working. Feel free to edit line, or rewrite code to make work correctly. Its a quick two page copy into Console Program.
Eventually, want number generator to work in a stream , while SeeNumber observes in a Console program for one minute.
Code follows this resource: Reactive Extensions
Goals which can be incorporated in code:
Make the Number Generator streaming
Also reading, are Subjects are good in RX? Feel free to modify code without subjects if true,
Main.cs
static void Main(string[] args)
{
var generateNumber = new GenerateNumber();
var seeNumber = new SeeNumber(generateNumber);
generateNumber.DivideByThreeSpotted.Subscribe(seeNumber.OnDivideByThreeSpotted);
Console.WriteLine(generateNumber.NumberValue);
Console.ReadKey();
}
Produce Number:
public class GenerateNumber
{
public int NumberValue { get; set; }
public GenerateNumber()
{
NumberValue = CreateData();
}
public Subject<GenerateNumber> divideByThreeSpotted = new Subject<GenerateNumber>();
public IObservable<GenerateNumber> DivideByThreeSpotted
{
get { return this.divideByThreeSpotted; }
}
public int CreateData()
{
Random random = new Random();
return random.Next(0, 100);
}
public void SpotDivideByThree(GenerateNumber generateNumber)
{
try
{
if (NumberValue % 3 == 0)
{
Console.WriteLine("Number Can be Divided by 3");
this.divideByThreeSpotted.OnNext(generateNumber);
}
}
catch (Exception exception)
{
this.divideByThreeSpotted.OnError(exception);
}
}
}
See Number:
public class SeeNumber : IDisposable
{
private IDisposable divideByThreeSpottedSubscription;
public SeeNumber(GenerateNumber generateNumber)
{
this.divideByThreeSpottedSubscription = generateNumber.DivideByThreeSpotted.Subscribe(this.OnDivideByThreeSpotted);
}
public void Dispose()
{
this.divideByThreeSpottedSubscription.Dispose();
}
public void OnDivideByThreeSpotted(GenerateNumber generateNumber)
{
GenerateNumber spottedDivisibleByThree = generateNumber;
}
}
Creating a simple example from tutorial,

Related

Why isn't all of the data being logged?

I have a List<Passenger> that contains information about their trips with my bus.
Each time I perform a trip I generate a random number of passengers (anywhere from 0 to 10) and I record them when they exit the bus.
I run the program anywhere between 10 to 100.000 times and record the passengers to the list only when they exit the bus. On the final stop, everyone gets kicked out.
I then use this code to write every passenger's trip to a text file.
Code
This code get called directly inside static void Main of Program.cs right after the cycles have completed running.
private static async Task LogData(StatManager statManager)
{
await File.WriteAllLinesAsync("test_output_1.txt", statManager.LogAllData());
}
Passenger.cs
public int ID {get; private set;}
public int stops {get; private set;} = 0;
public TripInfo trip {get; private set;}
public Passenger(int passenger_id, int stop_entered)
{
ID = passenger_id;
trip = new TripInfo();
trip.first_stop = stop_entered;
}
public void ExitBus(int exit_stop)
{
//get called once the passenger exits the bus
//at this point, the passenger is added to the main list
trip.exit_stop = exit_stop;
}
public void ArrivedAtStop()
{
stops++; //stop counter
}
public int[] GetStopsVisited()
{
int[] stops = new int[trip.stop_count];
for(int i = 0; i < trip.stop_count; i++)
{
stops[i] = trip.first_stop + i;
}
return stops;
}
public class TripInfo
{
public int first_stop;
public int exit_stop;
public int stop_count
{
get
{
if (exit_stop == null) return -1;
return exit_stop - first_stop;
}
}
}
StatManager.cs
public List<Passenger> LifetimePassengers = new List<Passenger>();
public int LifetimePassengerCount {get; private set;} = 0; //gets incremented in every cycle
private float mean;
private int LifetimeStops
{
get
{
return busManager.CurrentStop + 1; //gets an int that was incremented in every cycle
}
}
public String[] LogAllData()
{
List<String> toLog = new List<string>();
toLog.Add("LifetimeStops:"+LifetimeStops.ToString());
toLog.Add("LifetimePassengers:"+LifetimePassengerCount.ToString());
toLog.Add("IndividualPassengerData");
foreach(Passenger p in LifetimePassengers)
{
toLog.Add("-");
toLog.Add($"PassengerID:{p.ID}");
toLog.Add($"NumberOfStops:{p.stops}");
toLog.Add($"FirstStop:{p.trip.first_stop}");
toLog.Add($"ExitStop:{p.trip.exit_stop}");
string stops = String.Join(",", p.GetStopsVisited());
toLog.Add($"StopsVisited:[{stops}]");
}
return toLog.ToArray();
}
Output is as expected for the first lines but then I get this:
...
PassengerID:677
NumberOfStops:2
FirstStop:198
ExitStop:200
StopsVisited:[198,199]
PassengerID:678
NumberOfStops:2
FirstStop:198
ExitStop:200
StopsVisited:[198,199]
PassengerID:679
NumberOfStops:1
Fi
All data follows the above pattern of an ID and some trip information. But the data is incomplete. Above, the last passenger recorded is number 679 but the program ran for 1.000 stops and had a minimum of 1.000 passengers. Also the data stops abruptly with this unexpected Fi and does not complete the record of passenger number 679.
Furthermore, when I tried re-running the program, it did not output anything. I tried running it for amount of cycles: 5, 10 and 100, there was no difference and there was no output.
What can I do to solve this problem?
I think you need to follow this pattern calling async method from the main:
public static void Main()
{
MainAsync().GetAwaiter().GetResult();
}
private static async Task MainAsync()
{
//
var statManager = new StatManager();
// you code here ...
await LogData(statManager);
}
private static async Task LogData(StatManager statManager)
{
await File.WriteAllLinesAsync("test_output_1.txt",
statManager.LogAllData());
}

Can I create a pointer to poll a float from any source?

Is there a way to access all the different types of object inherited from the same class using the same reference in an object without hard-coding it?
I'm developing on unity and I want to add a module in my game that could watch any particular float in a GameObject to then change another float in another GameObject once it reaches a certain value.
As an example: A "Trigger" Object/Module which set the value of Hunger=1 in a brain Object when the value of Fullness<0.5 is reached in a stomach Object.
As I'll have a big number of possible combinations I don't want to hardcode it by creating a daughter of the Trigger Class for each of them.
My initial idea was to use pointers that would be directed to the good floats to watch/change upon initialization. But apparently, we can't use unsafe code inside iterators (IEnumerator) so I'm not sure how to poll the value of Fullness.
To give an example of what I would like :
public Class Trigger{
private float* ToPoll;
private float* ToChange;
public void SetTrigger(float* poll, float* change){
ToPoll = poll;
ToChange = change;
// the loop would be a IEnumerator, not a litteral loop
while(*ToPoll < 0.5f){
sleep(0.1)
}
*ToChange = 1f
}
}
void Main(){
Trigger trigger1, trigger2;
trigger1.SetTrigger(&Stomach.fullness, &Brain.hunger)
trigger2.SetTrigger(&Sun.activityLevel, &Earth.radiationLevel)
// ^ Literally any float from any object
}
Do you have any ideas how to or better ways to implement it?
Expanding on the answer from #kara, the following code implements independent Stomach and Brain objects, and uses Being to wire them up.
What Being knows about Stomach:
it has a NeedsFoodEvent
What Being knows about Brain
there is a OnRaiseIsHungryEvent (i.e. a "hungry" signal -- who cares where it came from)
it has a IsHungryEvent
Keep in mind that in a real implementation there would likely be other objects listening for those events. e.g. maybe you have an emotion system that would switch to "hangry" and a goal-based AI that would switch to food-seeking mode. Neither system would need to be aware of the other, but both could respond to signals from the Brain. In this trivial implementation the Being responds to the Stomach signal and both notifies and responds to the Brain.
The important take-away from this is not the specific method of raising and responding to events (in this case the default .Net mechanism) but the fact that neither object knows anything about the internals of the other (see the different implementations of HumanStomach and ZombieStomach) and instead the connection is wired up at a more appropriate level (Being in this case). Also note the reliance on interfaces, which allows us to do things like create hybrid beings (i.e. pairing a ZombieBrain with a HumanStomach).
Code was written/tested with .Net Core CLI as a console app, but it should be compatible with most any version of .Net > 3.5.
using System;
using System.Linq;
using System.Threading;
namespace so_example
{
public class Program
{
static void Main(string[] args)
{
var person1 = new Being("Human 1", new HumanBrain(), new HumanStomach());
var zombie1 = new Being("Zombie 1", new ZombieBrain(), new ZombieStomach());
var hybrid1 = new Being("Hybrid 1", new ZombieBrain(), new HumanStomach());
var hybrid2 = new Being("Hybrid 2", new HumanBrain(), new ZombieStomach());
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
public class HungryEventArgs : EventArgs
{
public string Message { get; set; }
}
public interface IStomach
{
event EventHandler<HungryEventArgs> NeedsFoodEvent;
}
public class Stomach : IStomach
{
public event EventHandler<HungryEventArgs> NeedsFoodEvent;
protected virtual void OnRaiseNeedsFoodEvent(HungryEventArgs e)
{
EventHandler<HungryEventArgs> handler = NeedsFoodEvent;
if (handler != null)
{
handler(this, e);
}
}
}
public class HumanStomach : Stomach
{
private Timer _hungerTimer;
public HumanStomach()
{
_hungerTimer = new Timer(o =>
{
// only trigger if breakfast, lunch or dinner (24h notation)
if (new [] { 8, 13, 19 }.Any(t => t == DateTime.Now.Hour))
{
OnRaiseNeedsFoodEvent(new HungryEventArgs { Message = "I'm empty!" });
}
else
{
Console.WriteLine("It's not mealtime");
}
}, null, 1000, 1000);
}
}
public class ZombieStomach : Stomach
{
private Timer _hungerTimer;
public ZombieStomach()
{
_hungerTimer = new Timer(o =>
{
OnRaiseNeedsFoodEvent(new HungryEventArgs { Message = "Need brains in stomach!" });
}, null, 1000, 1000);
}
}
public interface IBrain
{
event EventHandler<HungryEventArgs> IsHungryEvent;
void OnRaiseIsHungryEvent();
}
public class Brain : IBrain
{
public event EventHandler<HungryEventArgs> IsHungryEvent;
protected string _hungryMessage;
public void OnRaiseIsHungryEvent()
{
EventHandler<HungryEventArgs> handler = IsHungryEvent;
if (handler != null)
{
var e = new HungryEventArgs
{
Message = _hungryMessage
};
handler(this, e);
}
}
}
public class HumanBrain : Brain
{
public HumanBrain()
{
_hungryMessage = "Need food!";
}
}
public class ZombieBrain : Brain
{
public ZombieBrain()
{
_hungryMessage = "Braaaaaains!";
}
}
public class Being
{
protected readonly IBrain _brain;
protected readonly IStomach _stomach;
private readonly string _name;
public Being(string name, IBrain brain, IStomach stomach)
{
_stomach = stomach;
_brain = brain;
_name = name;
_stomach.NeedsFoodEvent += (s, e) =>
{
Console.WriteLine($"{_name}: {e.Message}");
_brain.OnRaiseIsHungryEvent();
};
_brain.IsHungryEvent += (s, e) =>
{
Console.WriteLine($"{_name}: {e.Message}");
};
}
}
}
Some Notes
To provide some output, I faked things in the 2 IStomach implementations. The HumanStomach creates a timer callback in the constructor which fires every 1 second and checks if the current hour is a meal hour. If it is, it raises the NeedsFoodEvent. The ZombieStomach also uses a callback every 1 second, but it just fires the NeedsFoodEvent every time. In a real Unity implementation you'd likely trigger the even based on some event from Unity -- an action the player took, after some preset amount of time, etc.
I'm not quite sure, what you want to do, but it sounds like you want to add triggers to you objects. In my understanding a trigger should be a delegate in this case.
Here an example how to define a delegate-type and add a list of triggers to your Brain-class.
Every brain can now have different triggers. I setup two derived brains to show you how to work with it:
public class TestBrain
{
private static int NextId = 1;
public TestBrain(List<MyTrigger> triggers)
{
this.Triggers = triggers;
this.Id = NextId++;
}
public int Id { get; private set; }
public int Hunger { get; set; }
public int StomachFullness { get; set; }
public List<MyTrigger> Triggers { get; private set; }
public void FireTriggers()
{
foreach (MyTrigger t in this.Triggers)
{
t.Invoke(this);
this.StomachFullness = 100;
}
}
public delegate void MyTrigger(TestBrain b);
}
public class HumanBrain : TestBrain
{
static readonly List<MyTrigger> defaultHumanTriggers = new List<MyTrigger>()
{
b => { if (b.StomachFullness < 50) { b.Hunger = 1; Console.WriteLine("{0} is hungry..", b.Id); } }
};
public HumanBrain() : base(defaultHumanTriggers)
{
}
}
public class RobotBrain : TestBrain
{
static readonly List<MyTrigger> defaultRobotTriggers = new List<MyTrigger>()
{
b => { if (b.StomachFullness < 50) { Console.WriteLine("{0} ignores hunger only want's some oil..", b.Id); } }
};
public RobotBrain() : base(defaultRobotTriggers)
{
}
}
static void Main()
{
// Create some test-data
List<TestBrain> brains = new List<TestBrain>()
{
new HumanBrain(),
new HumanBrain(),
new RobotBrain(),
new HumanBrain(),
};
Console.WriteLine(" - - - Output our Testdata - - -");
foreach (TestBrain b in brains)
{
Console.WriteLine("Status Brain {0} - Stomachfulness: {1} Hunger: {2}", b.Id, b.StomachFullness, b.Hunger);
}
Console.WriteLine(" - - - Empty stomachs - - -");
foreach (TestBrain b in brains)
{
b.StomachFullness = 0;
}
Console.WriteLine(" - - - Fire triggers - - -");
foreach (TestBrain b in brains)
{
b.FireTriggers();
}
Console.WriteLine(" - - - Output our Testdata - - -");
foreach (TestBrain b in brains)
{
Console.WriteLine("Status Brain {0} - Stomachfulness: {1} Hunger: {2}", b.Id, b.StomachFullness, b.Hunger);
}
}

C# add function dynamically

I have a program with some kind of "Macro Manager" that can (or at least should) save and play macros - one after the other. The macros are functions that the user can select by himself.
For example if the user wants to create a new macro he is going to do the following steps:
Click Button "Create"
Click Button "Select function"
Click another Button (The button holds a function behind it)
Play the macro
So as you can see, the user should be able to choose which function he wants to use dynamically.
I tried using delegates, but I dont really understand them (even though I have read about it)
So this is my code:
The MacroManager (Which holds the macros and plays them one after the other):
namespace ControlCenter
{
public class ControlCenterMacroManager
{
public List<ControlCenterMacro> macroList = new List<ControlCenterMacro>();
public string macroName;
public void runMacroList()
{
Thread t = new Thread(new ThreadStart(runMacroList_t));
t.Start();
}
public void runMacroList_t()
{
foreach (ControlCenterMacro macro in macroList)
{
Console.Write("Playing Macro: ");
macro.Run();
}
}
}
}
This would be the macro:
namespace ControlCenter
{
public class ControlCenterMacro
{
public bool isTimeout=false;
public int timemilli=0;
public delegate int macroAction();
public macroAction action;
public void Run()
{
if (isTimeout)
{
Console.Write("Waiting " + timemilli + " milliseconds ");
Thread.Sleep(timemilli / 4);
Console.Write(".");
Thread.Sleep(timemilli / 4);
Console.Write(".");
Thread.Sleep(timemilli / 4);
Console.Write(".");
Thread.Sleep(timemilli / 4);
Console.WriteLine(" done");
}
else
{
Console.WriteLine("Playing action " + action.ToString());
action();
}
}
}
}
And this is one of the possible functions I want to lay behind it (which is located in another class in another project):
public int turnOn()
{
Console.WriteLine("Einschalten:");
if(HomeMaticHttpRequest.sendRequest(this.url + "statechange.cgi?ise_id=" + this.RecieverId + "&new_value=true")!=null)
return 0;
return 1;
}
Does anybody know how I can solve this problem without too much hardcoding? (Want to keep it relatively dynamical)
Here is a small example stripped down to its essentials.
The Macro:
public class Macro
{
public delegate int macroAction();
public macroAction action;
public void Run()
{
action();
}
}
A container class with different methods:
public class Container
{
public int turnOn()
{
Console.WriteLine("Einschalten");
return 1;
}
public int turnOff()
{
Console.WriteLine("Ausschalten");
return 1;
}
}
And a small test programm which assigns different methods:
void Main()
{
Container c = new Container();
List<Macro> MacroList = new List<Macro>();
for (int i = 0; i < 10; i++)
{
Macro m = new Macro();
if (i % 2 == 0)
{
m.action = c.turnOn;
}
else
{
m.action = c.turnOff;
}
MacroList.Add(m);
}
foreach (var m in MacroList)
{
m.Run();
}
}
For the more general version I have to comeback tomorrow, gotta catch my train ;)

Can I bypass Console.ReadKey() issue when input is redirected?

I am a C# teacher and I wrote some automated HW checker for my students.
The students write C# Console Applications. My HW checker is based on input redirection so I can test their code on my own generated input.
The problem is that students sometimes end their program with a Console.ReadKey() instruction (They do so just to make the execution window not close when they ran the program under F5 - Debug). The Console.ReadKey() crashes when ran under input redirection with the following exception:
System.InvalidOperationException: Cannot read keys when either application does not have a console or when console input has been redirected from a file.
Do I have any way to "bypass" this problem (without altering the students code)? Maybe tell Console to ignore ReadKey instructions?
I see a clear case for a Dependency Injection pattern.
Let's build a simple example, with Read, ReadLine and WriteLine functionalities polymorphically: your students must write a homework in which a number given in the Console.ReadLine() must be parsed as int and returned to the Console Window.
Usually a student writes something like:
class Program
{
static void Main(string[] args)
{
var stringValue = Console.ReadLine();
int number;
if (int.TryParse(stringValue, out number))
Console.WriteLine($"The double of {number} is {number * 2}");
else
Console.WriteLine($"Wrong input! '{stringValue}' is not an integer!");
Console.Read();
}
}
Now, instead, create an interface for the Console functionalities:
public interface IOutput
{
void Read();
string ReadLine();
void WriteLine(string text);
}
A student must create a Homework class that wraps all the required homework code, using an IOutput instance in this way:
public class HomeWork
{
private IOutput _output;
public HomeWork(IOutput output)
{
_output = output;
}
public void Run()
{
_output.WriteLine("Give me an integer:");
var stringValue = _output.ReadLine();
int number;
if (int.TryParse(stringValue, out number))
_output.WriteLine($"The double of {number} is {number * 2}");
else
_output.WriteLine($"Wrong input! '{stringValue}' is not an integer!");
_output.Read();
}
}
The Main becomes:
static void Main(string[] args)
{
var h = new HomeWork(new ConsoleOutput());
h.Run();
}
You give them also the ConsoleOutput class:
public class ConsoleOutput : IOutput
{
public void Read()
{
Console.Read();
}
public string ReadLine()
{
return Console.ReadLine();
}
public void WriteLine(string text)
{
Console.WriteLine(text);
}
}
So the use it instead of call directly Console.Read() etc.
The student must pass to you not the entire Application, but only the Homework class.
You can create a test class that use the Homework class with some test implementations of IOutput like the followings:
public abstract class TestOutput : IOutput
{
public TestOutput()
{
Outputs = new List<string>();
}
public void Read()
{
//do nothing?
}
public abstract string ReadLine();
public void WriteLine(string text)
{
Outputs.Add(text);
}
public List<string> Outputs { get; set; }
}
public class TestOutputWithAValidNumber : TestOutput
{
public TestOutputWithAValidNumber(int value)
{
Value = value;
}
public override string ReadLine()
{
return Value.ToString();
}
public int Value { get; }
}
public class TestOutputWithNotValidNumber : TestOutput
{
public TestOutputWithNotValidNumber(string value)
{
Value = value;
}
public override string ReadLine()
{
return Value;
}
public string Value { get; }
}
The test class can be something like this:
[TestClass]
public class TestOutputClass
{
[TestMethod]
public void TestGoodNumber()
{
var testOutput = new TestOutputWithAValidNumber(1234);
var h = new HomeWork(testOutput);
h.Run();
Assert.AreEqual(1234, testOutput.Value);
Assert.AreEqual("Give me an integer:", testOutput.Outputs[0]);
Assert.AreEqual("The double of 1234 is 2468", testOutput.Outputs[1]);
}
[TestMethod]
public void TestWrongNumber()
{
var testOutput = new TestOutputWithNotValidNumber("foo");
var h = new HomeWork(testOutput);
h.Run();
Assert.AreEqual("foo", testOutput.Value);
Assert.AreEqual("Give me an integer:", testOutput.Outputs[0]);
Assert.AreEqual("Wrong input! 'foo' is not an integer!", testOutput.Outputs[1]);
}
}
If you need only to wrap the Console.Read() method, feel free to simplify all this code, but IMHO I thought that a wider view on this possible solution would have been useful anyway.
If the executables are in IL, you can create an easy application that uses ILDASM.
The key point is: disassemble the executable with ILDASM into a text file/stream, look for any call to Console.Read and remove it, than recompile it and run.

Access into global variable by Console.Readline() in C#

I'm trying to improve my program for Fibonacci numbers using of memoization:
public class MyGlobals
{
public long TotNum { get; set; }
public long[] MyNumbers { get; set; }
public void GetParam()
{
Console.Write("n = ");
this.TotNum = long.Parse(Console.ReadLine());
this.MyNumbers = new long[this.TotNum + 1];
// set all numbers to -1
for (int i = 0; i < this.MyNumbers.Length; i++)
{
this.MyNumbers[i] = -1;
}
}
}
class Program
{
static void Main(string[] args)
{
MyGlobals globVariable = new MyGlobals();
globVariable.GetParam();
long n = globVariable.TotNum;
Console.WriteLine("Fib ({0}) = {1}", n, Fibonacci(n));
Console.ReadKey();
}
static long Fibonacci(long n)
{
MyGlobals globVariable = new MyGlobals();
if (n <= 1)
{
return 1;
}
if (globVariable.MyNumbers[n] != -1)
{
return globVariable.MyNumbers[n];
}
else
{
globVariable.MyNumbers[n] = Fibonacci(n - 1) + Fibonacci(n - 2);
}
return globVariable.MyNumbers[n];
}
}
I'm trying to do something like feed an array by -1 in MyGlobals class for further using MyNumbers array in Fibonacci static method.
Until line where I'm starting to call recursive fibonacci method it holds MyNumbers array in memory. But in Fibonacci method, when I create new instance of MyGlobals class for calling MyNumbers array is this array empty... What I'm doing wrong. Can you anybody help me on this, please. Thank you very much in forward.
Declare globVariable as a static member of the Program class like so:
class Program
{
static MyGlobals globVariable = new MyGlobals();
static void Main(string[] args)
{
globVariable.GetParam();
long n = globVariable.TotNum;
Console.WriteLine("Fib ({0}) = {1}", n, Fibonacci(n));
Console.ReadKey();
}
static long Fibonacci(long n)
{
if (n <= 1)
{
return 1;
}
if (globVariable.MyNumbers[n] != -1)
{
return globVariable.MyNumbers[n];
}
else
{
globVariable.MyNumbers[n] = Fibonacci(n - 1) + Fibonacci(n - 2);
}
return globVariable.MyNumbers[n];
}
}
There is no such thing as global variables in C#. The problem you're having relates to instances of nonstatic classes.
You effectively have three separate units in your code:
One class that asks for input, holds this input and holds an array of result variables (MyGlobals). This is in fact way too much for a single class and should ultimately be split up.
One method that calculates Fibonacci numbers and stores them into the previous class (Fibonacci).
A Program class and Main() method which host your console application.
Now your problem is that you don't know how to access the array of inputs stored in 1 from method 2. There are various ways to solve that, each with their own cons and pros. The most obvious one is to pass a reference.
But before that, clean up your code: give classes and methods meaningful names, and extract logic into separate classes.
Here you'll remain with three classes:
public class FibonacciInput
{
public void GetParam()
{
// Your "MyGlobals" logic
}
}
Then the calculation logic:
public class FibonacciCalculator
{
public long Fibonacci(long index, long[] range)
{
// Your "Fibonacci()" logic
}
}
And the program:
class Program
{
static void Main(string[] args)
{
FibonacciInput input = new FibonacciInput();
FibonacciCalculator calculator = new FibonacciCalculator();
input.GetParam();
long n = input.TotNum;
Console.WriteLine("Fib ({0}) = {1}", n, calculator.Fibonacci(n, input.MyNumbers));
Console.ReadKey();
}
}
Now your calculator doesn't know anything about your input, and the need for "global variables" goes away.
The point is that the Fibonacci() method needs two things: the index (the Nth Fibonacci number it should calculate) and an array to work with (which you initialized on beforehand).
So by calling calculator.Fibonacci(n, input.MyNumbers), you solve all problems at once.
Well, may be it's not really answers your question but i'd refactor your code dividing it to logical parts where each part is only responsible for one thing :
UI
Global variables
Class that knows how to work with fibo sequence
Program (entry point)
Refactored code may look something among the lines of :
// Globals should be static
public static class MyGlobals
{
public static long TotNum { get; private set; }
public static long[] MyNumbers { get; private set; }
public static void SetNum(long num)
{
TotNum = num;
MyNumbers = new long[TotNum + 1];
}
}
// interacts with UI
public static class UIHelper
{
public static long GetParam()
{
Console.Write("n = ");
var number = long.Parse(Console.ReadLine());
return number;
}
}
// Knows how to calc fibo
static class Fibo
{
static long Calc(long[] nums, long n)
{
... calc fibonacci logic
}
}
class Program
{
static void Main(string[] args)
{
// now we can use them all
// first lets get value from console
var num = UIHelper.GetParam();
// set global variables with this value
MyGlobals.SetNum(num);
// output result :
Console.WriteLine("Fib ({0}) = {1}", n, Fibo.Calc(MyGlobals.MyNumbers, MyGlobals.TotalNum));
Console.ReadKey();
}
}
P.S.
Whether to send global values as parameters to Fibo.Calc() method or to access them directly from inside of it it's up to you. I vote for first option because it makes it easier to test this method by passing mock data.

Categories

Resources