Good evening,
Just to have a little context, I started C# just a few months ago and I am making a bank application with C# as an assignment.
I have 2 classes: Customer and Bank Employee that inherit from the abstract class Person. The Account class (basically savings, current, whatever) inherits from the Customer class.
UML
I only kept the attributes because the rest doesn't matter for what's to follow.
My problem is that i can't seem to understand what I am doing wrong with the AllAccounts list regrouping all the Accounts from the Customer.
Here is the thing, i mostly manipulate the AllAccounts list inside the Customer class and as soon as it's out of whatever method it was, it doesn't save any changes.
I checked by displaying the length of the list inside the method and outside of it (let it be in program.cs or Customer.cs). By default, the method creates 2 accounts so the first number displayed is 2. However the second number displayed is 0 and this is where I am lost.
For example, I have this method public Customer CreateCustomer() that returns a Customer class, the first line i would write is AllAccounts = new List<Account>();. I later found out that it wasn't working, I then decided to initialise the list in a constructor.
public Customer()
{
AllAccounts = new List<Account>();
}
It was still not keeping whatever changes i made to the AllAccounts list.
My latest attempt was to initialise AllAccounts list inside the main, which gave me an null error when trying to display the length.
I'd like to understand What I am missing and where I am wrong.
Thanks for reading.
EDIT:
Here are my attributes for Customer, the constructor and the CreateCustomer method:
Customer.cs
private int pinNumber { get; set; }
private string accountNumber { get; set; }
public List<Account> AllAccounts { get; set; }
public Customer()
{
AllAccounts = new List<Account>();
}
public Customer CreateCustomer()
{
string full = "accountnumber"; // Just a login thing, dont mind
int pin = 1; // same here
string path = "Customers";
string saving = path + "\\saving.txt";
string current = path + "\\current.txt";
AllAccounts.Add(new Account() { path = saving, name = "saving", total = 0 });
AllAccounts.Add(new Account() { path = current, name = "current", total = 0 });
return new Customer() { firstName = firstName, lastName = lastName, pinNumber = pin, accountNumber = full };
}
Inside program.cs, that's how I call the createcustomer method:
var Client = new Customer();
//get client info
AllCustomers.Add(Client.CreateCustomer());
After adding my customer to* AllCustomers*, the firstname, lastname are saved but not what was on AllAccounts.
When i run this:
Console.WriteLine(AllCustomers[0].AllAccounts[0].name);
It displays null basically, not even an error is shown it's just a null character.
By the way thanks for your replies!
Well the Issue is when you are returning new Customer() in CreateCustomer(). You are not passing the list which was created by CreateCustomer().
return new Customer() { firstName = firstName, lastName = lastName, pinNumber = pin, accountNumber = full,AllAccounts=AllAccounts };
So, right now you create a new Account list but its basically not being assigned to the customer, hence no account to any customer and once you create a new Customer, because of the constructor initializing of the new Account List all the previous data is lost.
Update your return statement and it would work
Related
I'm very new to C#, and the realm of programming. I've been carrying out some exercises in books and YouTube videos to wrap my head around many of these concepts.
Currently, I'm stuck on this issue. I have a small application for a Consignment Shop, and I was working on removing the hard coded sample data, and having the program read data from text files.
Here is my Vendor class:
public class Vendor
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Vendor(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
}
This essentially takes my .csv file of Vendors and pushes them into a string array, creates the object and fills it's properties with array values, then adds the item to a list of type Vendor. This method throws no errors.
private void ReadFromFile()
{
string line = "";
while ((line = myReader1.ReadLine()) != null)
{
string[] data = line.Split(',');
Vendor v = new Vendor(data[0], data[1]);
store.Vendors.Add(v);
}
}
When I try this same solution for adding Items to a list, I would like to pass in the "Owner" of the item, which is a property of type Vendor, located in my Items class. Since I couldn't get a working solution on passing an object as a parameter in constructor, I decided to stick with passing formal data types. I basically want to use the Vendor's properties of First Name & Last Name, and set those as the Item Owner's first and last name.
public class Item
{
public string Title { get; set; }
public decimal Price { get; set; }
public Vendor Owner { get; set; }
public Item(string title, decimal price, string fName, string lName)
{
Title = title;
Price = price;
Item.Owner.FirstName = fName; // this is what I want to do
Item.Owner.LastName = lName; // throws objref error
}
}
//Input file format: title,price,fname,lname
while ((line = myReader2.ReadLine()) != null)
{
string[] data2 = line.Split(',');
decimal price = decimal.Parse(data2[1]);
Item i = new Item(data2[0],price,data2[2],data2[3]);
store.Items.Add(i);
}
The strings make it into the array, but when I run the debugger and check my store.Items List, every property value is set except for Owner, which is null.
I know one solution could be to somehow combine fName+lName into one string, but I'm having a hard time understanding how my Item constructor needs to be set up in terms of which parameters it will accept. No matter what I try, the Oner property is never received a value, which causes the rest of my application to crash.
I've been working at this for a few hours, but I can't seem to come up with a working solution, or even a workaround to this scenario.
Any help is greatly appreciated.
Thanks!
I don't think your code even compiles, but what you want is this:
Owner = new Vendor(fName, lName);
This essentially creates a Vendor instance and assigns it to the Owner variable. Owner is otherwise uninitialized and null, that's why you get the exception.
instead of this:
Item.Owner.FirstName = fName; // this is what I want to do
Item.Owner.LastName = lName; // throws objref error
You have exception because Item.Owner is actually not created.
Fix it:
public Item(string title, decimal price, string fName, string lName)
{
Title = title;
Price = price;
Item.Owner = new Vendor(fName, lName);
}
Also: why do you write 'Item.Owner'? It isn't seemed to be static. Use just Owner.
In Java, if a class is a member of another class, you initialise it with new.
So in your constructor, you'd do the following:
public Item(string title, decimal price, string fName, string lName)
{
Title = title;
Price = price;
Owner = new Vendor(fName, lName);
I want to get some understanding about how exactly Automapper is working. I know the basic idea, before I just used so called ViewModels to send the information that the business needs extracted from one or more database tables. Now I'm working on a legacy project where Automapper is used and maybe it offers more than just that but for the given moment I want to undestand (be able) to map my Domain object(s) to my DTO object(s) or vice-versa, I'm not sure which one is the correct way to go since I'm not able to do it.
This is a simple example of a console project I've made to test some basic functionalities of Automapper:
Where the DTO_User.cs class is meant to be used to send a data to the front end. It looks like this:
public class DTO_User
{
public int ID { get; set; }
public string Name { get; set; }
}
And the User.cs is the class which represent the actual domain data :
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
}
So what I am trying to do. In my Program.cs I have a static method which creates some User obejcts:
public static List<Model.User> SeedUsers()
{
List<Model.User> users = new List<Model.User>()
{
new Model.User { ID = 1, Name = "Ivan", PhoneNumber = "1235436"},
new Model.User { ID = 2, Name = "Petkan", PhoneNumber = "00000000"},
new Model.User { ID = 3, Name = "Dragan", PhoneNumber = "11111111"},
new Model.User { ID = 4, Name = "Stoyan", PhoneNumber = "224545346"}
};
return users;
}
Then In my Main method I try to map this mocked data to my DTO List:
static void Main(string[] args)
{
Mapper.CreateMap<DTO.DTO_User, Model.User>();
//Mock user data as if it's taken from database
List<Model.User> users = new List<Model.User>();
users.AddRange(SeedUsers());//Simulate call to database
//Create List of DTO Users
List<DTO.DTO_User> dtoUsers = new List<DTO.DTO_User>();
//Now map the database users to our DTO Users
foreach (var user in users)
{
DTO.DTO_User u = Mapper.Map<Model.User, DTO.DTO_User>(user);
dtoUsers.Add(u);
}
}
I got the error inside the foreah loop here:
DTO.DTO_User u = Mapper.Map<Model.User, DTO.DTO_User>(user);
Saying that I have some invalid arguments. Obviously I don't really catch the idea how Automapper was meant to implement the actual mapping. The code above is what was looking most natural to me. I know that this is pretty basic so an actual solution won't be too challenging but I would really appreciate if someone explains to me where my logic cracks and what is the idea behind the working code.
Trying adding an additional mapping:
Mapper.CreateMap<Model.User, DTO.DTO_User>();
and changing your Map invocation to the following:
DTO.DTO_User u = Mapper.Map<DTO.DTO_User>(user);
from what i understand in other posts i know that my objects use same place in memory but how to separate these objects?
i tried to use new but it didn't work or i didn't used it correctly.
Note that i didnt paste setter and getter here.
class Supermarket
{
List<Product> _products = new List<Product>{ };
List<Customer> _customers = new List<Customer>{ };
}
class Customer
{
List<Product> _purchased= new List<Product>{ };
}
class Product
{
string _id;
string _name;
DateTime _expireDate;
int _cost;
int _count;
}
i add one Product in one Method.
Product product = new Product(...);
supermarket.Products.Add(product);
and in another method i want to copy the Product from Supermarket.Products
to Supermarket.Customers.Purchased. so i want a copy but i cant get it.
here i want to make Copy but it does not work.
Product product = supermarket.Products[productIndex];
supermarket.Customers[customerIndex].Purchased.Add(product);
now the problem is when i change Product properties in Customer class , Product properties inside Supermarket will change too.
for example
supermarket.Customers[customerIndex].Purchased.Last().Count = ...
//now the Product supermarket.Products[productIndex] will change too witch is unwanted
The reason why it is not working is because you are doing shallow copy by just adding the pointer of product object into the list, not all properties. So if you change one, another will be affected accordingly.
You can use deep copy following this answer, but this way you have to mark your class as [Serializable]. The simplest way which I think is to use Json serializer:
public static class CloneHelper
{
public static T Clone<T>(T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
}
var copyProduct = CloneHelper.Clone<Product>(product);
Or simply, you can manage by yourself as the below code, then it works:
Product product = supermarket.Products[productIndex];
Product copyProduct = new Product() {
Id = product.Id,
Name = product.Name,
ExpireDate = product.ExpireDate,
Cost = product.Cost,
Count = product.Count
};
supermarket.Customers[customerIndex].Purchased.Add(copyProduct);
I have been trying to create a program that allows the user to edit things such as the supply of mp3 players which have a base value stored in the program:
public struct MP3_Players
{
public int ID { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public int MBsize { get; set; }
public decimal Price { get; set; }
public int Supply { get; set; }
}
MP3_Players player1 = new MP3_Players
{
ID = 1,
Make = "GET Technologies .inc",
Model = "HF 410",
MBsize = 4096,
Price = 129.95m,
Supply = 500
};
MP3_Players player2 = new MP3_Players
{
ID = 2,
Make = "Microsoft",
Model = "SOFT1",
MBsize = 1028,
Price = 432.99m,
Supply = 500
};
MP3_Players player3 = new MP3_Players
{
ID = 3,
Make = "PEAR",
Model = "APPLE3",
MBsize = 2056,
Price = 130.00m,
Supply = 500
};
MP3_Players player4 = new MP3_Players
{
ID = 4,
Make = "logitech",
Model = "DEF0",
MBsize = 2056,
Price = 53.35m,
Supply = 500
};
MP3_Players player5 = new MP3_Players
{
ID = 5,
Make = "Sennheiser",
Model = "HEIS1",
MBsize = 2056,
Price = 399.95m,
Supply = 500
};
Now making a method with a list isn't really an issue, I imagine it goes as follows:
public static void mutate()
{
List<MP3_Players> PlayerList = new List<MP3_Players>;
Playerlist.Add(player1);
Playerlist.Add(player2);
Playerlist.Add(player3);
Playerlist.Add(player4);
Playerlist.Add(player5);
}
My first question is simply a matter of improvement of code, but I suppose many people reading this will understand the problems I'm running into, primarily that player1 is not static, does this mean I will have to individually make every player static or is there an easier way?
The primary issue however lies with my attempts to create a small program to change the Supply, The idea is for a user to enter an ID and then allow them to edit the supply, this went well for me when I was using an array but I am having issues understanding how to use data in a list<> and change it(basically trying to reach the values stored in the list from other methods if possible at all).
An easier way would be to initialize the list by
List<MP3_Players> PlayerList = new MP3Players[]{
new MP3_Players()
{
ID = 1,
Make = "GET Technologies .inc",
Model = "HF 410",
MBsize = 4096,
Price = 129.95m,
Supply = 500
}, <-- include more instances of MP3_Players here
}.ToList();
and furthermore, the indexer [] can be used to access the elements in a list very similar to an array.
To solve your "list problem" you could use classes and a dictionary:
public class MP3_Players
{
/* ... */
}
public static void mutate()
{
var PlayerList = new Dictionary<int, MP3_Players>;
PlayerList.Add(player1.ID, player1);
PlayerList.Add(player2.ID, player2);
PlayerList.Add(player3.ID, player3);
PlayerList.Add(player4.ID, player4);
PlayerList.Add(player5.ID, player5);
}
Then you can access them via their ID and change them:
var player = PlayerList[ID];
player.Supply--;
player.Price -= 10;
BUT to solve your bigger problem of "persistency" you should think of a "data-store" to persist you data, e.g. Entity Framework and a DB.
Have you considered using collection initializer for inlining the creation of the PlayerList?
Where static is concerned, static method cannot access non static instance members.
One way is to create dictionary like other user explain if the ID of the players are Unique, if they are not doesn't start this approach. This is requirement of dictionary !
The other way using List.
List<MP3_Players> newList = PlayerList.FindAll(x=>x.Model == Apple3);
newList.ToList().ForEach(x => x.Storage = 30);
This will return every Player with Model Apple3 and second row will change all the values for Storage.
In C#, Structs are Immutable. This means that they can't be edited. If you wish to make a change to an item, then it needs to be replaced by a totally new item. You can avoid this by using a class.
One problem that I have ran into editing collections in an enumeration is that the collection was modified and the enumeration can no longer continue. This was happening because I was using a foreach loop that evaluates each item in the collection. I avoided it by using for loops and fetching the element from the list using its index and performing my edit there.
Code below defines a ChargeCustomer class that contains an array of type "customers". I want to be able to create an object with either 1 "customer" or 2 "customers" based on the constructor parameters. Is this the right way to do so in C#:
public class ChargeCustomer
{
private Customer[] customers;
public ChargeCustomer( string aName, string bName, int charge )
{
customers = new Customer[2];
customers[0] = new Customer(aName, charge);
customers[1] = new Customer(bName, charge);
}
public ChargeCustomer( string bName, int charge )
{
customers = new Customer[1];
customers[0] = new Customer( bName, charge );
}
}
Thanks!
Note: This assumes that DropBox was a mis-paste in the original question.
You can move things around and have 1 constructor using params for any number of names, like this:
public class ChargeCustomer
{
private Customer[] customers;
public ChargeCustomer( int charge, params string[] names)
{
customers = new Customer[names.Length];
for(int i = 0; i < names.Length; i++) {
customers[i] = new Customer(names[i], charge);
}
}
}
Using this approach you just pass the charge first and any number of customer names, like this:
new ChargeCustomer(20, "Bill", "Joe", "Ned", "Ted", "Monkey");
It will create an array the correct size and fill it using the same charge for all, and 1 Customer per name by looping through the names passed in. All that being said, there's probably a much simpler overall solution to your problem, but without making changes outside the Customer class (aside from the constructor calls), this would be the simplest approach/smallest change.