Optimal way of approaching and coding multiple classes [closed] - c#

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);
}

Related

How to create a structure with embedded fields?

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)

Update an object from a list of destination derived classes with an object from a list of derived source classes using a generic converter

I have a list of source classes derived from a base source class and a list with destination classes derived from a base destination class. There is only one destination class corresponding to a source class. I want to make a generic converter which updates an existing destination object, given his corresponding source object.
Updated completely:
I have the following code:
using System;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
S1 newItem = new S1()
{
Age = 11,
Name = "John"
};
D1 oldItem = new D1()
{
Age = 10
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<S1, D1> convertor = new Convertor<S1, D1>(newItem, oldItem);
S2 newItem2 = new S2()
{
City = "London",
Name = "Lynda"
};
D2 oldItem2 = new D2()
{
City = "Paris"
};
Convertor<S2, D2> convertor2 = new Convertor<S2, D2>(newItem2, oldItem2);
Console.ReadKey();
}
}
public abstract class SourceDomain
{
public string Name { get; set; }
internal abstract void SetItem<Y>(Y oldItem) where Y : DestinationDomain;
}
public class S1 : SourceDomain
{
public int Age { get; set; }
internal override void SetItem<Y>(Y oldItem)
{
Console.WriteLine("here I want to update the age of oldItem (10) with the new value (11)");
//oldItem.Age = Age;
}
}
public class S2 : SourceDomain
{
public string City { get; set; }
internal override void SetItem<Y>(Y oldItem)
{
Console.WriteLine("here I want to update the city of oldItem Paris with the new value London");
// oldItem.City = City;
}
}
public class DestinationDomain { }
public class D1 : DestinationDomain
{
public int Age { get; set; }
}
public class D2 : DestinationDomain
{
public string City { get; set; }
}
public class Convertor<X, Y> where X : SourceDomain where Y : DestinationDomain
{
protected X item;
protected Y oldItem;
public Convertor(X newObject, Y oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of item type, the proper method, not the base one.
item.SetItem(oldItem);
}
}
}
SourceDomain and DestinationDomain are base classes and there are a lot of derived classes for each of them S1, S2, D1, D2, etc.
This converter receives two classes as types and two objects of that classes and tries to update the destination item of type Y with source item of type X.
In the above example, I want to change update the age of the D1 oldItem variable with 11, and the City oldItem2 with the "London" value, but I cannot access that properties in SetItem method.
This needs to be done with a combination of inheritance and generics, and we'll make the two work together with generic type constraints.
Here are the requirements as I understand them:
You've got some data you want to copy from Source to Destination; one kind of data has an Age, one has a City, maybe another has a Poodle or a SwimmingPool. We'll define an interface that says: "This is a data object which can copy its own properties from another object of the same type", and we'll put all our data in little classes which know how to copy themselves. The "I can copy things like me" interface doesn't know what properties will be copied; it just requires the concrete class to implement a method that knows those details internally. As far as this example goes it could be a base class, but my assumption is the “copyability” isn’t the core indentity of these objects. It’s not what they represent; it’s just one thing we need to be able to do with them along the way.
The other things we need are a "source thing", and a "destination thing". A source thing just needs to provide a data object that can be copied. A destination thing just needs to receive a data object that can be copied.
You confused yourself by trying to mix up the sources and destinations with the data items. If you're going crazy trying to make your class do two contradictory things at once, try breaking it up into two classes that each does one thing.
You never do anything with your SourceDomain Name property, so I won't either. If you need to, I'll leave that as an exercise.
public interface ICopyable<T>
{
void CopyFrom(T other);
}
internal class Program
{
private static void Main(string[] args)
{
var newItem = new SourceDomain<Person>
{
Item = new Person { Age = 11 },
Name = "John"
};
var oldItem = new DestinationDomain<Person>
{
Item = new Person { Age = 10 }
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<Person> convertor = new Convertor<Person>(newItem, oldItem);
var newItem2 = new SourceDomain<Location>()
{
Item = new Location { City = "London" },
Name = "Lynda"
};
var oldItem2 = new DestinationDomain<Location>()
{
Item = new Location { City = "Paris" }
};
Convertor<Location> convertor2 = new Convertor<Location>(newItem2, oldItem2);
Console.ReadKey();
}
}
public class SourceDomain<T>
{
public string Name { get; set; }
public T Item { get; set; }
}
public class DestinationDomain<T> where T : ICopyable<T>, new()
{
public string Name { get; set; }
public T Item { get; set; }
public void CopyItemFrom(T other)
{
if (Item == null)
{
Item = new T();
}
Item.CopyFrom(other);
}
}
// A person is a thing which can turn itself into a copy of another Person.
// You could define a class Wombat : ICopyable<Locomotive>, if you wanted to be
// able to convert Locomotives to Wombats. You'd just add another CopyFrom()
// overload, public void CopyFrom(Locomotive other).
public class Person : ICopyable<Person>
{
public int Age { get; set; }
public void CopyFrom(Person other)
{
Age = other.Age;
}
}
public class Location : ICopyable<Location>
{
public String City { get; set; }
public void CopyFrom(Location other)
{
City = other.City;
}
}
public class Convertor<X> where X : ICopyable<X>, new()
{
protected SourceDomain<X> item;
protected DestinationDomain<X> oldItem;
public Convertor(SourceDomain<X> newObject, DestinationDomain<X> oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of item type, the proper method, not the base one.
//newObject.Data = oldItem.Data;
oldItem.CopyItemFrom(item.Item);
}
}
Homework:
Modify this code so DestinationDomain.CopyItemFrom() receives the source itself, not the source's item.
I think it's better the way I wrote it. Think of reasons why I might have thought that.
Seriously, find out what ref does, and never again use a keyword in your code if you are only guessing about what it might mean. Don't just throw code at the wall, hoping it sticks. You'll get yourself in a lot of frustrating trouble that way.
Finally i have done this:
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
S1 newItem = new S1()
{
Age = 11,
Name = "John"
};
D1 oldItem = new D1()
{
Age = 10
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<S1, D1> convertor = new Convertor<S1, D1>(newItem, oldItem);
S2 newItem2 = new S2()
{
City = "London",
Name = "Lynda"
};
D2 oldItem2 = new D2()
{
City = "Paris"
};
Convertor<S2, D2> convertor2 = new Convertor<S2, D2>(newItem2, oldItem2);
Console.ReadKey();
}
}
public interface ICopyable<T>
{
void CopyFrom(T other);
}
public abstract class SourceDomain
{
public string Name { get; set; }
}
public class S1 : SourceDomain
{
public int Age { get; set; }
}
public class S2 : SourceDomain
{
public string City { get; set; }
}
public class DestinationDomain { }
public class D1 : DestinationDomain, ICopyable<S1>
{
public int Age { get; set; }
public void CopyFrom(S1 other)
{
Console.WriteLine("oldItem.Age " + Age + " new Age; = " + other.Age);
Age = other.Age;
Console.WriteLine("oldItem.Age " + Age + " new Age; = " + other.Age);
}
}
public class D2 : DestinationDomain, ICopyable<S2>
{
public string City { get; set; }
public void CopyFrom(S2 other)
{
City = other.City;
Console.WriteLine(" oldItem.City = City;");
}
}
public class Convertor<X, Y> where X : SourceDomain where Y : DestinationDomain, ICopyable<X>
{
protected X item;
protected Y oldItem;
public Convertor(X newObject, Y oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of X type, the proper method, not the base one.
oldItem.CopyFrom(item);
Console.WriteLine(item);
}
}
}

How do i display List<object> with items in console C# [duplicate]

This question already has answers here:
Print List of objects to Console
(3 answers)
Closed 4 years ago.
can someone please help me...
Im trying to display the items in the list on the console.
the current output is displaying my two sub classes: Grocery and FreshProduce.
I have also added a image showing the current result below.
any help is much appreciated.
namespace ShoppingList
{
class ShoppingList
{
static void Main(string[] args)
{
Grocery myGrocery = new Grocery("Bread", 1);
FreshProduce myFreshProduce = new FreshProduce("Orange", 1);
List<object> myShoppingList = new List<object>();
myShoppingList.Add(myGrocery);
myShoppingList.Add(myFreshProduce);
PrintValues(myShoppingList, '\t');
}
public static void PrintValues(IEnumerable myList, char mySeparator)
{
foreach (Object obj in myList)
Console.Write("{0}{1}", mySeparator, obj);
Console.WriteLine();
}
public abstract class Product
{
protected string Name;
protected int Quantity;
}
public class Grocery : Product
{
public Grocery(string groceryName, int groceryQuantity)
{
Name = groceryName;
Quantity = groceryQuantity;
}
}
public class FreshProduce : Product
{
public FreshProduce(string freshProduceName, int freshProduceQuantity)
{
Name = freshProduceName;
Quantity = freshProduceQuantity;
}
}
}
}
If you need to print the details of the Product, you should override the ToString() method. You can do this by using the below implementation of the Product class
public abstract class Product {
protected string Name;
protected int Quantity;
public override string ToString() {
return $"Name = {Name}, Quantity = {Quantity}";
}
}
While I am at it, you might as well make some other minor improvements to your code. See the full code below
namespace ShoppingList {
class ShoppingList {
static void Main(string[] args) {
Grocery myGrocery = new Grocery("Bread", 1);
FreshProduce myFreshProduce = new FreshProduce("Orange", 1);
List<Product> myShoppingList = new List<Product>();
myShoppingList.Add(myGrocery);
myShoppingList.Add(myFreshProduce);
PrintValues(myShoppingList, "\t");
}
// instead of IEnumerable, you should use IEnumerable<Product> for better type checking
public static void PrintValues(IEnumerable<Product> myList, string mySeparator) {
// string.Join does exactly what you are trying to do using a loop
Console.WriteLine(string.Join(mySeparator, myList));
}
public abstract class Product {
protected string Name;
protected int Quantity;
public override string ToString() {
return $"Name = {Name}, Quantity = {Quantity}";
}
}
public class Grocery : Product {
public Grocery(string groceryName, int groceryQuantity) {
Name = groceryName;
Quantity = groceryQuantity;
}
}
public class FreshProduce : Product {
public FreshProduce(string freshProduceName, int freshProduceQuantity) {
Name = freshProduceName;
Quantity = freshProduceQuantity;
}
}
}
}

Check if List<T> element contains an item with a Particular Property Value

public class Item
{
public List<int> val { get; set; }
public double support { get; set; }
}
I declare variable:
List<Item> t = new List<Item>();
t.Add(new Item(){val = new List<int>(){1,2,3};support=.1);
var b = new Item();
b.val = t[0].val;
b.support=t[0].support;
t.Contain(b) // return false???
I'm try with linq
t.Any(a=>a.val==b.val) // I'm get error Expression cannot contain lambda expressions
3 possibilities come to mind:
You could implement IEquatable<T>:
public class Item: IEquatable<Item>
{
public List<int> val { get; set; }
public double support { get; set; }
public bool Equals(Item other)
{
return
this.support == other.support &&
this.val.SequenceEqual(other.val);
}
}
and now t.Contains(b) will return true.
If you cannot modify the Item class you could write a custom EqualityComparer:
public class ItemEqualityComparer : IEqualityComparer<Item>
{
private ItemEqualityComparer()
{
}
public static IEqualityComparer<Item> Instance
{
get
{
return new ItemEqualityComparer();
}
}
public bool Equals(Item x, Item y)
{
return
x.support == y.support &&
x.val.SequenceEqual(y.val);
}
public int GetHashCode(Item obj)
{
int hash = 27;
hash += (13 * hash) + obj.support.GetHashCode();
foreach (var item in obj.val)
{
hash += (13 * hash) + item.GetHashCode();
}
return hash;
}
}
and then t.Contains(b) will also return true.
Or if you prefer simply do it naively:
List<Item> t = new List<Item>();
t.Add(new Item { val = new List<int>(){1,2,3}, support=.1 });
var b = new Item();
b.val = t[0].val;
b.support = t[0].support;
bool equals = t.All(item => item.support == b.support && item.val.SequenceEqual(b.val));
Console.WriteLine(equals);
Your t.Any(a=>a.val == b.val) is correct.
The error you get is from the quick watch or expression window in the debugger, not from the compiler. Visual Studio's expression evaluator does not handle lambdas. However, it's still valid c# code, and will do what you want.
It's your earlier line that's a problem:
t.Add(new Item(){val = new List<int>(){1,2,3};support=.1);
This is a mixture of various different bits of syntax. It should be:
t.Add(new Item(){val = new List<int>(){1,2,3}, support=.1});
... although preferably with better property names, etc. Then the rest should work - although you need to do something with the result of Any. The Any call itself is valid. Here's a short but complete program which works:
using System;
using System.Collections.Generic;
using System.Linq;
public class Item
{
public List<int> Values { get; set; }
public double Support { get; set; }
}
class Test
{
static void Main()
{
List<Item> list = new List<Item>
{
new Item { Values = new List<int>{1, 2, 3},
Support = 0.1 }
};
var check = new Item { Values = list[0].Values,
Support = list[0].Support };
bool found = list.Any(a => a.Values == check.Values);
Console.WriteLine(found);
}
}
Note that this is performing a reference comparison between the two lists - if you created a different list with the same values (1, 2, 3), that wouldn't be found. You'd need to use a.Values.SequenceEqual(b.Values) or something similar.
Your Item class should implemenet the IEquatable interface:
class Item : IEquatable<Item>{
public List<int> val { get; set; }
public double support { get; set; }
public bool Equals(Item item){
return this.support.Equals(item.support) && this.val.SequenceEqual(item.val);
}
}
Then the Contains() method should work well.
You can correct your "t.Contain(b)" to t.Contains(b, new ItemEqualityComparer()) from System.Linq where ItemEqualityComparer will be your class, which will implement IEqualityComparer<Item>

WPF C#. put observablecollection into List<string>

I have observablecollection which i fill with textboxes on button click event. In my Project is one class where i have list >> public List _RoomNumber = new List(); i want to just send observablecollection value into _RoomNumber list. For example if observablecollection cotains this 4 values : 15, 20, 2323, 3232 i want _RoomNumber context be same so this : 15, 20, 2323, 3232
I hope my question is clear.
This my observablecollection :
ObservableCollection<CheckInData> _CheckInCollection = new ObservableCollection<CheckInData>();
public ObservableCollection<CheckInData> CheckInCollection
{
get { return _CheckInCollection; }
}
public class CheckInData
{
public string RoomNumber { get; set; }
public decimal Price { get; set; }
public string Currecny { get; set; }
public decimal Discount { get; set; }
public string CheckOut { get; set; }
public int TotalDay { get; set; }
public decimal TotalPrice { get; set; }
public int CheckOutYear { get; set; }
public int CheckOutMonth { get; set; }
public int CheckOutDay { get; set; }
public Boolean IncToday { get; set; }
}
this is how im trying to put in list. Problem is that observablecollection contains 102 and 305. _RoomNumber only gets value '1'. please help
private void btnPrintInvoice_Click(object sender, RoutedEventArgs e)
{
//This is Class where my List _RoomNumber is
DataToExcel.Invoice inv = new DataToExcel.Invoice();
foreach (CheckInData coll in CheckInCollection)
{
for (int i = 0; i < _CheckInCollection.Count; i++)
{
inv._RoomNumber.Add(coll.RoomNumber[i].ToString());
}
}
}
You need to make small modification. Try this:
private void btnPrintInvoice_Click(object sender, RoutedEventArgs e)
{
//This is Class where my List _RoomNumber is
DataToExcel.Invoice inv = new DataToExcel.Invoice();
foreach (CheckInData coll in CheckInCollection)
{
inv._RoomNumber.Add(coll.RoomNumber.ToString());
}
}
You don't need to access RoomNumber with index. It is not a collection.
You can use
var roomnumbers = CheckInCollection.Select(x => x.RoomNumber);
inv._RoomNumber = new List(roomnumbers);
Or if you want to reuse the existing List instance,
inv._RoomNumber.Clear();
inv._RoomNumber.AddRange(roomnumbers);
but this seems to be not your case.
Note that in your code, your both inner and outer loops iterate over the same collection :-)
using System.Linq;
...
ObservableCollection<string> ListA = new ObservableCollection<string>();
List<string> ListB = ListA.ToList<string>();

Categories

Resources