I am looking for information about that in the internet but with no success. The goal is to realize a sort of dataset of 10 subject (sub_1, sub_2... sub_10), each of them has done 3 kind of activities (walk, run, jump) for three time each (trial_1... trial_3) with relative scores. I would like to access these information like:
variable = dataset.sub_1.jump.trial_2.score;
or, at least:
variable = dataset.sub[0].task[2].trial[1].score;
So, the structure would be a tree structure. Until now I only realized a structure with "parallel fields":
struct dataset
{
public string[] sub; // 1 to 10 subjects
public string[] task; // 1 to 3 tasks
public string[] trial; // 1 to 3 trials
public int score; // the score of the above combination
}
Any idea?
This problem can be solved in many ways.
My solution has one drawback, there is no check if user exceeded Score arrays capacity.
I guess database tag has nothing to do with this question
using System;
using System.Linq;
namespace ConsoleApp
{
public abstract class Task
{
public string Name { get; set; }
public int TotalScore { get { return Score.Sum(); } }
public int[] Score { get; set; } = new int[3];
}
public class Walk : Task { }
public class Run : Task { }
public class Jump : Task { }
public class Subject
{
public Walk Walk { get; set; } = new();
public Run Run { get; set; } = new();
public Jump Jump { get; set; } = new();
public int TotalScore { get { return Walk.TotalScore + Run.TotalScore + Jump.TotalScore; }}
}
class Program
{
static void Main(string[] args)
{
var subject = new Subject();
// Adding score to specific trials
subject.Run.Score[0] = 50;
subject.Run.Score[1] = 40;
subject.Run.Score[2] = 60;
subject.Jump.Score[0] = 40;
subject.Jump.Score[1] = 80;
subject.Jump.Score[2] = 100;
// Output score of 1. trial for Walk task
Console.WriteLine(subject.Walk.Score[0]);
// Output total score as a sum of all trials for Jump task
Console.WriteLine(subject.Jump.TotalScore);
// Output total score as a sum of all trials in all tasks
Console.WriteLine(subject.TotalScore);
// ERROR CASE: this will be exception
subject.Jump.Score[3] = 100;
}
}
}
using System;
using System.Collections.Generic;
namespace ConsoleApp
{
public class Trial
{
public Trial(int score)
{
Score = score;
}
public int Score { get; set; }
}
public class Task
{
public List<Trial> Trials { get; } = new List<Trial>();
}
public class Subject
{
public Dictionary<string, Task> Tasks { get; } = new Dictionary<string, Task>();
public Subject()
{
Tasks.Add("walk", new Task());
Tasks.Add("run", new Task());
Tasks.Add("jump", new Task());
}
}
class Program
{
static void Main(string[] args)
{
Subject player1 = new Subject();
player1.Tasks["run"].Trials.Add(new Trial(score: 3));
Console.WriteLine(player1.Tasks["run"].Trials[0].Score);
}
}
}
Maybe a class for everything is too much, but maybe you want to add a description property for tasks one day or a timestamp for the trial. Then it's ok.
public class Subject
{
private Dictionary<string,Activity> _activities { get; }= new Dictionary<string, Activity>();
public Activity this[string activity]
{
get
{
if (!_activities.Keys.Contains(activity))
_activities[activity] = new Activity();
return _activities[activity];
}
set
{
_activities[activity] = value;
}
}
public int Score => _activities.Values.Sum(x => x.Score);
}
public class Activity
{
private Dictionary<int, Trial> _trials { get; } = new Dictionary<int, Trial>();
public Trial this[int trial]
{
get
{
if (!_trials.Keys.Contains(trial))
_trials[trial] = new Trial();
return _trials[trial];
}
set
{
_trials[trial] = value;
}
}
public int Score => _trials.Values.Sum(x => x.Score);
}
public class Trial
{
public int Score { get; set; }
}
public class Answer
{
public void DoSomething()
{
Subject Mindy = new Subject();
Mindy["curling"][1].Score = 5;
Mindy["bowling"][1].Score = 290;
Console.WriteLine(Mindy.Score);
}
}
This is what I would guess you think you need... but from your question I think you're still new to C# and might want to rethink your concept. It looks like a very database-oriented way of looking at the problem, so maybe you might want to take a look at dapper to more closely match your database.
Also, avoid using the classname Task, this can imo only cause confusion if you ever start using multithreading (System.Threading.Task is a .NET framework component)
Related
I have a class that contains Range[] as property and Range class is a self referencing class. I used [JsonIgnore] to prevent StackoverflowException but it works for only Serialize not Deserialize. How can I fix this?
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace testoverflow
{
class Program
{
public static void Main(string[] args)
{
GlobalVariable.Json = "[{\"TotalBytesReceived\":0,\"Id\":\"b03750fb291a46708f8e1a7409553075\",\"NofThread\":8,\"Speed\":0,\"Progress\":0.0,\"FilePath\":\"C:\\\\Users\\\\kafeinaltor\\\\Downloads\",\"RangeDir\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\",\"Url\":\"http://ipv4.download.thinkbroadband.com/20MB.zip\",\"Ranges\":[{\"Start\":0,\"End\":9223372036854775806,\"TotalBytesReceived\":0,\"IsDownloaded\":false,\"FileId\":\"87cd7715dc0740c1b82ddd681bf2523d\",\"Size\":9223372036854775807,\"Status\":4,\"IsIdle\":false,\"SaveDir\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\",\"FilePath\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\\\\87cd7715dc0740c1b82ddd681bf2523d\",\"Md5Checksum\":null}],\"Info\":null,\"DownloadRequestMessage\":null}]";
var a = new MTDO();
Console.WriteLine(GlobalVariable.Json);
Console.ReadKey(true);
}
public static class GlobalVariable
{
public static string Json { get; set; }
}
public class MTDO
{
public MTDO()
{
Ranges = new Range[]
{
new Range(0L, 100L, ""),
new Range(101L, 200L, "")
};
Id = Guid.NewGuid().ToString("N");
Reminder.AddOrUpdate(this);
}
public string Id { get; set; }
public Range[] Ranges{ get; set; }
}
public class Range
{
public long Start { get; set; }
public long End { get; set; }
public string SaveDir { get; set; }
public long TotalBytesReceived{ get; set; }
public Range(long start, long end, string saveDir)
{
this.Start = start;
this.End = end;
this.SaveDir = Guid.NewGuid().ToString();
}
[JsonIgnore]
public Range Remaining
{
get
{
return new Range(Start + TotalBytesReceived, End, SaveDir);
}
}
}
public class Reminder
{
public Reminder()
{
}
public static void AddOrUpdate(MTDO mtdo)
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
var exists = list.Any(x => x.Id == mtdo.Id);
if (!exists)
list.Add(mtdo);
else
{
var i = list.Select((x, j) => new {val = x, index = j})
.First(x => x.val.Id == mtdo.Id).index;
list[i] = mtdo;
}
WriteJson(list);
}
public static List<MTDO> ReadList()
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
return list;
}
static string Read()
{
try
{
return GlobalVariable.Json;
}
catch
{
return "";
}
}
static void WriteJson(List<MTDO> list)
{
GlobalVariable.Json = JsonConvert.SerializeObject(list);
}
}
}
}
UPDATE: I have updated myquestion adding minimum reproducable code in Console Application. You can copy/paste and run directly.
The problem is that you have an infinite recursion:
You call MTDO constructor
Inside MTDO constructor you call Reminder.AddOrUpdate(this);
Inside that method you have var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
Which calls MTDO constructor again (step 1)
These steps keep repeating until you get StackOverflowException.
may I ask (as a novice) how do I call a method of a namespace, from another? Thank you for setting up an example if possible..
For example: (1) how do I set the properties of the MY_PRIMARY class to use them and (2) how do I call the AddNumbers method while in the MY_SECONDARY namespace? Thank you..
using.. etc
namespace MY_PRIMARY
{
public partial class SomethingHere
{
public Boolean holiday { get; set; } = false;
public int age { get; set; } = 18;
//etc...
}
class Program
{
private static void Main()
{
// some code here.. and..
public int AddNumbers(int number1, int number2)
{
int result = number1 + number2;
return result;
}
}
};
namespace MY_SECONDARY
{
public partial class SomethingElseHere
{
public Boolean holiday { get; set; } = false;
public int age { get; set; } = 18;
//etc...
}
class Program
{
static void Main()
{
// some code here..
}
// and..
Program outer = new Program();
outer.AddNumbers(3, 18); // <--- this is failing..
}
}
;
Namespaces are meant to group objects semantically. I'm kind of confused why you have 2 program classes. It would make more sense to have one class library, and one program. Anyway...
Suppose you have an Object1 in namespace Program.First,
And an Object2 in Program.Second
Object2 has a method named someMethod.
What you would do to call this method is
a) either add "using Program.Second", on you first class.
b) make an instance of Program.Second.Object2, and call the method on that.
https://www.programiz.com/csharp-programming/namespaces
So suppose you want to make an object of Program() do this:
using System;
namespace MY_PRIMARY
{
public partial class SomethingHere
{
public Boolean holiday { get; set; } = false;
public int age { get; set; } = 18;
//etc...
}
public class Program
{
public int AddNumbers(int number1, int number2)
{
int result = number1 + number2;
return result;
}
}
}
namespace MY_SECONDARY
{
public partial class SomethingElseHere
{
public Boolean holiday { get; set; } = false;
public int age { get; set; } = 18;
//etc...
}
class Program
{
static void Main()
{
MY_PRIMARY.Program outer = new MY_PRIMARY.Program();
outer.AddNumbers(3, 18);
}
}
}
(EDIT) updated my answer, i copied your code and saw that your namespaces were not closed off, therefor, you had nested namespaces, and classes in there. plus, some of the code was directly in your class instead of in a function.
Also, don't define 2 Main() methods, that's the entrypoint of the application.
...A little modification in POSITIONS of functions and classes... please, see:
using Alias = MY_PRIMARY.Program;
namespace MY_PRIMARY
{
public partial class SomethingHere
{
public Boolean holiday { get; set; } = false;
public int age { get; set; } = 18;
//etc...
}
public class Program
{
private static void Main()
{
// some code here.. and..
}
public int AddNumbers(int number1, int number2)
{
int result = number1 + number2;
return result;
}
};
namespace MY_SECONDARY
{
public partial class SomethingElseHere
{
public Boolean holiday { get; set; } = false;
public int age { get; set; } = 18;
//etc...
}
class Program
{
static void Main()
{
// some code here..
// and..
Alias outer = new Alias();
outer.AddNumbers(3, 18); // <--- OKAY...
}
}
}
}
See more:
Using namespaces (C# Programming Guide)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have multiple classes that interact with each other and I got them to work and its diplaying properly but I cant help but feel that theres an optimal, cleaner and maybe even simpler way of coding this. Function is simple that it displays Product Name, Duration till Sold and Cost.
public class Item
{
private string name;
private int duration;
private int cost
public Item(string n, int d, double c)
{
Name = n;
Duration = d;
Cost = c;
}
}
Second class:
class Inventory
{
private List<Item> item = new List<item>();
public void AddItem(Item p) // Add item
{
item.Add(p);
}
public Item this[int i]
{
get
{
return item[i];
}
set
{
item[i] = value;
}
}
}
In my Form.cs I got this:
private void Form1_Load(object sender, EventArgs e)
{
{
var myInventory = new Inventory();
var i1 = new Item("iPod", 200, 9);
var i2 = new Item("Samsung", 700, 5);
var i3 = new Item("Nokia", 100, 17);
var i4 = new Item("Motorolla", 50, 50);
myInventory.AddItem(i1);
myInventory.AddItem(i2);
myInventory.AddItem(i3);
myInventory.AddItem(i4);
lstProduct.Items.Add(myInventory[0]); // Add items into listbox via indexing
lstProduct.Items.Add(myInventory[1]);
lstProduct.Items.Add(myInventory[2]);
lstProduct.Items.Add(myInventory[3]);
}
Completely new to programming so Im still learning. Im mainly concerned with my Form.cs and the way I coded it but I welcome any feedback/suggestions if you have a better idea on how to code the other classes I made.
Thanks !
Here's your code
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var myInventory = new Inventory();
var i1 = new Item{name = "iPod", cost = 200,duration = 9};
var i2 = new Item{name = "Samsung",cost = 700,duration = 5};
var i3 = new Item{name = "Nokia", cost = 100, duration = 17};
var i4 = new Item{name = "Motorolla",cost = 50, duration = 50};
myInventory.InventoryItems.Add(i1);
myInventory.InventoryItems.Add(i2);
myInventory.InventoryItems.Add(i3);
myInventory.InventoryItems.Add(i4);
foreach (var inventoryItem in myInventory.InventoryItems)
{
lstProduct.Items.Add(inventoryItem)
}
}
}
}
public class Item
{
public string name { get; set; }
public int duration { get; set; }
public int cost { get; set; }
}
class Inventory
{
public List<Item> InventoryItems { get; set; }
}
Use public (auto) property, instead of just private field, if you'd like to access it later.
// for class Item
public string Name { get; private set; }
public int Duration { get; private set; }
public int Cost { get; private set; }
// for class Inventory
public List<Item> Items { get; private set; } = new List<Item>();
Don't abbreviate variable name. Make it easy to read.
For plural items, end your variable name with "s"
Override ToString() so that you can display the object instance easily.
// For Class Item
public override string ToString()
{
return $"Name={Name}, Duration={Duration}, Cost={Cost}";
}
// For Inventory Item
public override string ToString()
{
return string.Join(Environment.NewLine, Items);
}
Use loop to iterate
// in Load event handler
foreach(var item in myInventory.Items)
{
lstProduct.Items.Add(item);
}
I want to create a class with a property that "variably" points to some other property in another class.
Imagine a class (called "Limiter") with several integer properties (Limit1, Limit2, etc).
I now want a second class ("LimitWatcher") which can "watch" one of those limits. But I want to be able to set which particular limit it is watching in the constructor. I eventually want several instances of LimitWatcher, each one pointing to a separate Limit. The Limit values themselves may change after the Watchers have been instantiated, but the watcher must always see the current value of the Limit that it is watching. So basically, I want to store a reference to an integer.
I know I can accomplish this using reflection (see example below), but I feel as though there might be a simpler way.
using System;
namespace ConsoleApplication4
{
public class Limiter
{
public int limit1 { get; set; } = 10;
public int limit2 { get; set; } = 20;
public void Update()
{
limit1++;
limit2++;
}
}
public class LimitWatcher
{
public LimitWatcher(Limiter lim, string propName)
{
myLimiter = lim;
limitName = propName;
}
private Limiter myLimiter { get; }
public string limitName { get; set; }
//can I do this without reflection:
public int FooLimit { get { return (int)typeof(Limiter).GetProperty(limitName).GetValue(myLimiter); } }
}
class Program
{
static void Main(string[] args)
{
Limiter lim = new ConsoleApplication4.Limiter();
LimitWatcher w1 = new LimitWatcher(lim, nameof(lim.limit1));
LimitWatcher w2 = new LimitWatcher(lim, nameof(lim.limit2));
lim.Update();
Console.WriteLine($"1st watcher sees {w1.FooLimit}"); //11
Console.WriteLine($"2nd watcher sees {w2.FooLimit}"); //21
Console.ReadKey();
}
}
}
You could use a Func int the constructor, something like:
private Limiter limiter;
private Func<Limiter, int> propertyAccesor;
public LimitWatcher(Limiter lim, string propName, Func<Limiter, int> propertyAccesor)
{
this.propertyAccesor = propertyAccesor;
}
public bool LimitExceeded()
{
int propertyValue = propertyAccesor(limiter);
return propertyValue > 20;
}
You could use dynamic expressions:
using System.Linq.Expressions;
public class LimitWatcher
{
public LimitWatcher(Limiter lim, string propName)
{
myLimiter = lim;
limitName = propName;
var parameter = Expression.Parameter(typeof(Limiter), "x");
var member = Expression.Property(parameter, propName);
var finalExpression = Expression.Lambda<Func<Limiter, int>>(member, parameter);
getter = finalExpression.Compile();
}
private Func<Limiter, int> getter;
private Limiter myLimiter { get; }
public string limitName { get; set; }
public int FooLimit { get { return getter(myLimiter); } }
}
Inspired by this article
I have an Class Translator which has two instances of Parser(Options options) - an input parser, and output parser. They each get their own options.
Each parser has a list of ElementParser(Options option) which passes the options down.
If the each parser has a hundred elements, these means there are over a hundred refs to each option instance.
This seems excessive.
The obvious answer is to create a static Parser.Options property, but traditional wisdom says to stay away from them.
So is there a better way to architect this?
Here is a working sample:
public class Options {
public int Value { get; set; }
}
public class ElementParser {
public object ElementData { get; set; }
public ElementParser(Options options) {
this.Options = options;
}
public Options Options { get; set; }
public void DoesSomethingWithOptions() {
if (Options.Value == 1)
{
//Do something();
}
else
{
//Do something else();
}
}
}
public class SegmentParser{
public object SegmentData { get; set; }
public Options Options { get; set; }
public List<ElementParser> ElementParsers { get; set; }
public SegmentParser(Options options) {
this.Options = options;
}
public void AddABunchOfElements() {
this.ElementParsers = new List<ElementParser>() {new ElementParser(this.Options), new ElementParser(this.Options)};
}
}
class Program
{
static void Main(string[] args) {
var options1 = new Options() {Value = 1};
var options2 = new Options() {Value = 2};
var segment1 = new SegmentParser(options1);
segment1.AddABunchOfElements();
var segment2 = new SegmentParser(options2);
segment2.AddABunchOfElements();
//There are now 3 references of each options. If there were 100 elements, there would be over 200 references.
}
}
Here is a second attempt using a static property. Notice that the Parser class is subclassed, so there is really only one instance of the static property. This sample does work correctly.
public class Options
{
public int Value { get; set; }
}
public class Parser{
}
public class Parser1 : Parser
{
public Parser1(Options options) {
Options = options;
}
public static Options Options { get; set; }
}
public class Parser2 : Parser {
public Parser2(Options options) {
Options = options;
}
public static Options Options { get; set; }
}
class Program
{
static void Main(string[] args) {
var options1 = new Options();
options1.Value = 1;
var options2 = new Options();
options2.Value = 2;
var test1 = new Parser1(options1);
var test2 = new Parser2(options2);
Console.WriteLine(Parser1.Options.Value); //Should be 1
Console.WriteLine(Parser2.Options.Value); //Should be 2;
}
}
There's nothing wrong with what you've posted. A few hundred references to an object is not that big in the grand scheme of things.
I'd only make Options static if there is only one Options(which there isn't)
If Options is more associated with Segment than it is with Element than your Element might not even need to have the Options property, it can simply use Segment's or it can take an Options parameter in it's method.
Right now your program is abstracted enough that it's impossible to tell whether or not that would be appropriate, but it's something to keep in mind.
Segment and Element seem to be just plain DTO's, which should thus not be able with their own construction.
AddABunchOfElements() belongs in a SegmentWriter instance, containing one or more Options.