How to fix a StackOverflow exception in Get/Set? - c#

Bear in mind that this is my first day of learning C#; this is also my first compiled language, so I am absolutely not used to the concept of 'types'. I am coming from Python.
It seems strongly typed languages are an order of magnitude more difficult than Python... v_v'
I get a StackOverflow exception, but I don't know why:
static void Main(string[] args)
{
Dictionary<string, int> init = new Dictionary<string,int>();
init["stepId"] = 250;
init["offset"] = 13;
init["inc"] = 113;
init["danger"] = 0;
StepGenerator gen = new StepGenerator(init);
Console.Write("Next: {0}", gen.Step["stepId"]);
Console.Read();
The error is seemingly here:
public Dictionary<string, int> Step
{
get { return Step; }
set
{
Dictionary<string, int> step = value;
// It complains about this line, and suggests an infinite recursion.
step["rnd"] = genRnd(rnlut[step["stepId"]], step["offset"]);
step["limit"] = genDangerLimit(step["rnd"]);
step["enc"] = genEnc(step["danger"], step["limit"]);
Step = step;
}
Full:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace rePlanner
{
public class StepGenerator
{
// snipped array size:
private static readonly int[] rnlut = new int[] {0xB1}
enum Input
{
B,
G,
};
enum Encounter
{
No,
Yes,
}
enum Type
{
Run,
Walk,
Stutter,
Unit,
}
public Dictionary<string, int> Step
{
get { return Step; }
set
{
Dictionary<string, int> step = value;
step["rnd"] = genRnd(rnlut[step["stepId"]], step["offset"]);
step["limit"] = genDangerLimit(step["rnd"]);
step["enc"] = genEnc(step["danger"], step["limit"]);
Step = step;
}
}
internal int stepId {get; set;}
internal int offset { get; set;}
internal int danger { get; set; }
internal int rnd { get; set; }
internal int dangerLimit { get; set; }
internal int enc { get; set; }
internal int type { get; set; }
internal int units { get; set; }
public int input { get; set; }
// Constructor.
public StepGenerator(Dictionary<string, int> step)
{
this.Step = step;
}
private int genStepId(int oldStepId)
{
return (oldStepId + 2) & 0xFF;
}
private int genOffset(int oldOffset, int stepId)
{
if (stepId == 0)
{
int offset = (oldOffset + 13) & 0xFF;
}
else
{
offset = oldOffset;
}
return offset;
}
private int genDanger(int oldDanger, int oldInc)
{
danger = oldDanger;
danger += oldInc;
if (danger > 65535)
{
danger = oldInc;
}
return danger;
}
private int genRnd(int rnlut, int offset)
{
return (rnlut - offset) & 0xFF;
}
private int genDangerLimit(int rnd)
{
return ((rnd + 1) * 256);
}
private int genEnc(int danger, int dangerLimit)
{
if(danger > dangerLimit)
{
return (int)Encounter.Yes;
}
return (int)Encounter.No;
}
public Dictionary<string, int> next()
{
Dictionary<string, int> step = this.Step;
step["stepId"] = genStepId(this.Step["stepId"]);
step["offset"] = genOffset(this.Step["offset"], this.Step["stepId"]);
step["danger"] = genDanger(this.Step["danger"], this.Step["inc"]);
step["rnd"] = genRnd(rnlut[step["stepId"]], step["offset"]);
step["limit"] = genDangerLimit(step["rnd"]);
step["enc"] = genEnc(step["danger"], step["limit"]);
this.Step = step;
return step;
}
}
}

You're calling the setter on Step repeatedly with with line
Step = step;
This causes infinite recursion.
I think that you need to make your Step property the getter and setter for a private step member variable. First of all, remove
Dictionary<string, int> step = value;
from the Step setter. Make step a private member variable of StepGenerator:
private Dictionary<string, int> step;
Change your Step property to be:
public Dictionary<string, int> Step
{
get { return this.step; }
set
{
this.step = value;
this.step["rnd"] = genRnd(rnlut[step["stepId"]], step["offset"]);
this.step["limit"] = genDangerLimit(step["rnd"]);
this.step["enc"] = genEnc(step["danger"], step["limit"]);
}
}

Related

SortedDictionary key Object duplicate Problem

I have a SortedDictionary with Object as key, which implements the IComparable interface,
but the result is not correct.
here is the code
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace TestApp {
public class Program
{
public class UserPrice : IComparable<UserPrice>
{
public string Wxid { get; set; }
public int Num { get; set; }
public int Price{ get; set; }
public DateTime PriceTime { get; set; }
public int CompareTo(UserPrice other)
{
if (Wxid == other.Wxid)
{
return 0;
}
if (Price != other.Price)
{
return other.Price.CompareTo(Price);
}
return PriceTime.CompareTo(other.PriceTime);
}
public override string ToString()
{
return String.Format("wxid={0}, num={1}, price={2}, priceTime={3}", Wxid, Num, Price, PriceTime);
}
}
private SortedDictionary<UserPrice, int> sortedPriceDict = new SortedDictionary<UserPrice, int>();
private BlockingCollection<UserPrice> chan = new BlockingCollection<UserPrice>();
private void MockMessage()
{
sortedPriceDict = new SortedDictionary<UserPrice, int>();
var task = Task.Run((Action)MockRecvMsg);
for (var i = 0; i < 10; i++)
{
var j = i;
Task.Run(() => MockSendMsg(j));
}
task.Wait();
}
private void MockRecvMsg()
{
while (true)
{
var p = chan.Take();
sortedPriceDict[p] = 1;
//Console.WriteLine(sortedPriceDict.Count + "," + p);
if(sortedPriceDict.Count > 10)
{
break;
}
}
foreach(var up in sortedPriceDict){
Console.WriteLine(up);
}
}
private async void MockSendMsg(int i)
{
var wxId = String.Format("user_{0}", i);
var rand = new Random();
var basePrice = 320;
while(true)
{
var up = new UserPrice();
up.Wxid = wxId;
up.Price = rand.Next(basePrice, basePrice + 100) * 100;
up.Num = rand.Next(1, 10);
up.PriceTime = DateTime.Now;
//Console.WriteLine(up);
chan.Add(up);
await Task.Delay(rand.Next(1, 5) * 1000);
}
}
public static void Main()
{
var main = new Program();
main.MockMessage();
}
}
}
I want to sort by [Price desc, PriceTime asc], user price with the same Wxid should by unique in the SortedDictionary, I start 10 Tasks to produce messages from 10 users, and 1 consumer to save the messages into the sortedDictionary, but after run for a while, the program will stop, because the dictionary's count is > 10, so what's wrong with my code ? Do I miss anything?

Randomizing Instances of Object in List Error CS1503 in C#

I am creating a console app in c#. The apps purpose is to create robots, randomly assign 5 tasks once the robot is created, then display the robots total time etc. I have a class for BotTask and for Robot.
Having trouble with the following:
I am initializing each individual BotTask then attempting to load them into a list, to randomize them and return 5 BotTask's that can be assigned to a Robot.
I was thinking if each BotTask has an index property: I can randomize an integer then use that index property to select which BotTask is called by random.
When I try this I am receiving error code CS1503 (Arguement 1: cannot convert from 'int' to 'BotOMat.BotTask') and am unsure if I am trying to complete this process the correct way.
Here is the code I have written for the BotTask class:
public class BotTask
{
//initialize bot tasks
public static readonly BotTask DISHES = new BotTask("Dishes", "Do the dishes", 1000, 1);
public static readonly BotTask SWEEP = new BotTask("Sweep", "Sweep the house", 3000, 2);
public static readonly BotTask LAUNDRY = new BotTask("Laundry", "Do the laundry", 10000, 3);
public static readonly BotTask RECYCLING = new BotTask("Recycling", "Take out the recycling", 4000, 4);
public static readonly BotTask SAMMICH = new BotTask("Sammich", "Make a sammich", 7000, 5);
public static readonly BotTask LAWN = new BotTask("Lawn", "Mow the lawn", 20000, 6);
public static readonly BotTask RAKE = new BotTask("Rake", "Rake the leaves", 18000, 7);
public static readonly BotTask BATH = new BotTask("Bath", "Give the dog a bath", 14500, 8);
public static readonly BotTask BAKE = new BotTask("Bake", "Bake some cookies", 8000, 9);
public static readonly BotTask WASH = new BotTask("Wash", "Wash the car", 20000, 10);
public string Name { get; private set; }
public string Description { get; private set; }
public int Duration { get; private set; }
public int Index { get; private set; }
private BotTask(string name, string description, int duration, int index)
{
Name = name;
Description = description;
Duration = duration;
Index = index;
}
public static List<BotTask> randomizeBotTasks()
{
var loadBotTasks = new List<BotTask> { DISHES, SWEEP, LAUNDRY, RECYCLING, SAMMICH, LAWN, RAKE, BATH, BAKE, WASH };
int i = 1;
List<BotTask> randomizedBotTasks = new List<BotTask>();
while (i <= 5)
{
var random = new Random();
int index = random.Next(loadBotTasks.Count);
randomizedBotTasks.Add(index);
i++;
}
return randomizedBotTasks;
}
Without intentionally adding a second question here I would like to return this list of BotTasks to my Robot Class. So after user creates a Robot, 5 randomized BotTasks will be assigned to it.
Here is how I am trying to achieve this in my Robot class:
public class Robot
{
public string BotName { get; set; }
public RobotType BotType { get; set; }
public string BotTypeDescription => BotType.GetDescription();
public TimeSpan TimeElapsed { get; set; }
private readonly List<BotTask> _tasks = new List<BotTask>();
//public IEnumerable<BotTask> Tasks => _tasks;
public Robot(string botName, RobotType botType, TimeSpan timeElapsed = default)
{
this.BotName = botName;
this.BotType = botType;
TimeElapsed = timeElapsed;
}
public static void CreateRobot()
{
var robotsList = new List<Robot>();
//loop until there are no more robots
while (true)
{
Console.Write("Enter robot name: ");
var robotName = Console.ReadLine();
if (string.IsNullOrEmpty(robotName))
{
break; //empty robot, time to list things out
}
//RobotType? robotType = null;
RobotType? robotType = null;
while (!robotType.HasValue)
{
robotType = GetResponseUsingEnum<RobotType>("Robots");
}
var robot = new Robot(robotName, robotType.Value);
robotsList.Add(robot);
}
//At this point, we have a fully populated list of robots, each with some tasks
foreach (var robot in robotsList)
{
robot.Show();
}
}
public static T? GetResponseUsingEnum<T>(string prompt) where T : struct, Enum
{
//Loop until a good answer (or no answer)
while (true)
{
Console.WriteLine($"{prompt}: Please enter one of:");
var values = (T[])Enum.GetValues(typeof(T));
foreach (var enumValue in values)
{
var description = enumValue.GetDescription<T>();
var intValue = Convert.ToInt32(enumValue);
Console.WriteLine($"{intValue}: {description}");
}
Console.Write(">> ");
var response = Console.ReadLine();
if (string.IsNullOrEmpty(response))
{
return (T?)null;
}
if (Enum.TryParse<T>(response, out var val))
{
if (values.Contains(val))
{
Console.WriteLine($"You answered: {val}");
return val;
}
}
}
}
Appreciate any help in advance - thank you.
You can't add integer value to List<BotTask>
Use this:
public static List<BotTask> randomizeBotTasks()
{
var loadBotTasks = new List<BotTask> { DISHES, SWEEP, LAUNDRY, RECYCLING, SAMMICH, LAWN, RAKE, BATH, BAKE, WASH };
int i = 1;
List<BotTask> randomizedBotTasks = new List<BotTask>();
while (i <= 5)
{
var random = new Random();
int index = random.Next(loadBotTasks.Count);
randomizedBotTasks.Add(loadBotTasks[index]);
i++;
}
return randomizedBotTasks;
}

How to generalize a property pattern

I have classes that has multiple properties which have well-defined name and function but have the same implementation. For example:
class Stats
{
private int attack;
public int Attack
{
get =>
HasBuff ? attack + 1 : attack;
set
{
if (value < 1 || value > 10)
throw new ArgumentOutOfRangeException("Invalid value");
attack = value;
}
}
public int Defense {...}
public int Speed {...}
}
Where Defense and Speed are to be implemented just like Attack . How can I generalize this structure to avoid redundancy and make changes easier?
Make another class to generalize stats:
public class Stat
{
public bool HasBuff { get; set; }
private int _stat;
public int Score
{
get => HasBuff ? _stat + 1 : _stat;
set => _stat = value;
}
}
Then just use that for each of your skills:
public class CombatStats
{
public Stat Attack { get; } = new Stat();
public Stat Defense { get; } = new Stat();
public Stat Speed { get; } = new Stat();
}
Calling code would look like this:
var ninja = new Ninja();
ninja.skills = new CombatStats();
var attackStrength = ninja.skills.Attack.Score;
As further improvement, implicit operators can be used to avoid object creation and call to Score:
public class Stat
{
...
public static implicit operator int(Stat stat)
{
return stat.Score;
}
public static implicit operator Stat(int value)
{
return new Stat()
{
Score = value
};
}
}
This makes the change transparent to client code written w.r.t. to the example in the question:
ninja.skills = new CombatStats(){
Attack = 5,
Defense = 2
}
int attack = ninja.skills.Attack;
One approach to consider:
class Stats
{
// other existing code here
private int defense;
public int Defense
{
get
{
return GetValue(defense);
}
set
{
SetValue(value, ref defense);
}
}
private int GetValue(int value)
{
return HasBuff ? value + 1 : value;
}
private void SetValue(int value, ref int target)
{
if (value < 1 || value > 10)
throw new ArgumentOutOfRangeException("Invalid value");
target = value;
}
}
Attack etc will now be basically the same as Defence but passing in attack rather than defense to GetValue and SetValue.
I would go with composition
Stat:
public class Stats
{
private readonly StatProperty _defense;
private readonly StatProperty _attack;
private readonly StatProperty _speed;
public Stats()
{
_defense = new StatProperty(this);
_attack = new StatProperty(this);
_speed = new StatProperty(this);
}
public int Defense
{
get => _defense.Value;
set => _defense.Value = value;
}
public int Attack
{
get => _attack.Value;
set => _attack.Value = value;
}
public int Speed
{
get => _speed.Value;
set => _speed.Value = value;
}
public bool HasBuff { get; set; }
}
StatProperty:
public class StatProperty
{
public Stats Stats { get; }
public StatProperty(Stats stats)
{
Stats = stats;
}
private int _value = 1;
public int Value
{
get => Stats.HasBuff ? _value + 1 : _value;
set
{
if (value < 1 || value > 10)
throw new ArgumentOutOfRangeException("Invalid value");
_value = value;
}
}
}
I would need more details to know if it is the best option.
you also could make StatProperty as internal if don't want to show it outside of your library or nested private class if you want to use this just on the class Stats

C# - Sum integer in Array using recursive

So i'm currently trying to calculate the sum of all bags in the array using a recursive method. I'm sure it's easy, but I can't seem to get my head around it. Any assistance would be appreciated! - Cheers.
class Program
{
static void Main(string[] args)
{
List<Bag> bags = new List<Bag>();
bags.Add(new Bag("Blue", 25));
bags.Add(new Bag("Red", 35));
bags.Add(new Bag("White", 30));
int totalVolume = CalcTotalVolume(bags);
Console.WriteLine("Total volume of bags: {0}", totalVolume);
}
static int CalcTotalVolume(List<Bag> bagList)
{
//resursive method
//1. base case is when the list is empty
if (bagList.Count == 0)
{
return 0;
}
else
{
List<int> subList = bagList.GetRange(1, bagList.Volume - 1);
int subTotal = CalcTotalVolume(subList);
int total = bagList[1] + subTotal;
return total;
}
}
}//end of class Program
class Bag
{
public string Colour { get; set; }
public int Volume { get; set; }
public Bag(string co, int vo)
{
Colour = co;
Volume = vo;
}
}
Obviously a loop is a lot more efficient, but just for a kata, this is sort of interesting...
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Bag> bags = new List<Bag>();
bags.Add(new Bag("Blue", 25));
bags.Add(new Bag("Red", 35));
bags.Add(new Bag("White", 30));
int totalVolume = CalcTotalVolume(bags);
Console.WriteLine("Total volume of bags: {0}", totalVolume);
Console.ReadKey(true);
}
static int CalcTotalVolume(IEnumerable<Bag> bags)
{
//resursive method
//1. base case is when the list is empty
var bag = bags.FirstOrDefault();
if (bag == null) return 0;
var subList = bags.Skip(1);
return bag.Volume + CalcTotalVolume(subList);
}
}
class Bag
{
public string Colour { get; set; }
public int Volume { get; set; }
public Bag(string co, int vo)
{
Colour = co;
Volume = vo;
}
}
}
It would be interesting to know what kind of recursion you want. For example, the following also uses a recursive method but it amounts to a simple summing loop:
class Bag
{
public string Colour { get; }
public int Volume { get; }
public Bag(string c, int v)
{
Colour = c;
Volume = v;
}
}
class Program
{
static int CalcTotalVolumeIdx(List<Bag> bags, int i, int sum)
{
return (i >= bags.Count) ? sum :
CalcTotalVolumeIdx(bags, i + 1, sum + bags[i].Volume);
}
static int CalcTotalVolume(List<Bag> bags)
{
return CalcTotalVolumeIdx(bags, 0, 0);
}
static void Main(string[] args)
{
List<Bag> bags = new List<Bag>();
bags.Add(new Bag("Blue", 25));
bags.Add(new Bag("Red", 35));
bags.Add(new Bag("White", 30));
int totalVolume = CalcTotalVolume(bags);
Console.WriteLine("Total volume of bags: {0}", totalVolume);
}
}
As a side note, F# would actually compile the function CalcTotalVolumeIdx() into a while loop since this type of recursion is a well-known pattern that can be efficiently converted.
Edited to reflect Brian's comment. Thank you!

Is there a more elegant way to sum multiple properties?

I have a class which contains multiple properties of type Int32:
public class MyClass
{
public int C1 { get; set; }
public int C2 { get; set; }
public int C3 { get; set; }
.
.
.
public int Cn { get; set; }
}
I want to sum all this properties. Instead of doing:
int sum = C1 + C2 + C3 + ... + Cn
is there a more efficient/elegant method?
You can fake it, but I'm not sure how useful it is:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
var test = new MyClass();
// ...
int sum = test.All().Sum();
}
}
public class MyClass
{
public int C1 { get; set; }
public int C2 { get; set; }
public int C3 { get; set; }
// ...
public int Cn { get; set; }
public IEnumerable<int> All()
{
yield return C1;
yield return C2;
yield return C3;
// ...
yield return Cn;
}
}
}
If you really want to perform the sum without having to type each property you can use reflection to iterate through your properties but this is involves a big performance cost. However, for fun you can do something like this:
var item = new MyClass();
// Populate the values somehow
var result = item.GetType().GetProperties()
.Where(pi => pi.PropertyType == typeof(Int32))
.Select(pi => Convert.ToInt32(pi.GetValue(item, null)))
.Sum();
PS: Don't forget to add using System.Reflection; directive.
Maybe you can use an array or a data structure which has the IEnumarable interfaces vs a custom class. Then you can use linq to do Sum().
If there's a strong enough need to store the values in separate members (properties, fields), then yes, that's the only way. If you have a list of numbers however, store them in a list, not in separate members.
Or, ugly:
new[]{C1,C2,C3,C4}.Sum()
But more characters than the single "+" anyway.
public class MyClass
{
readonly int[] _cs = new int[n];
public int[] Cs { get { return _cs; } }
public int C1 { get { return Cs[0]; } set { Cs[0] = value; } }
public int C2 { get { return Cs[1]; } set { Cs[1] = value; } }
public int C3 { get { return Cs[2]; } set { Cs[2] = value; } }
.
.
.
public int Cn { get { return Cs[n-1]; } set { Cs[n-1] = value; } }
}
Now you can use Enumerable.Sum with MyClass.Cs, and you can still map C1, C2, ... to database fields.

Categories

Resources