I'm writing some code where I have some information about customers stored in an array called members (id, initials). I then ask the user for their id and initials and match the inputs to the stored information from array members. If they match I move on. However I get an error in my coding: "an object reference is required to access non-static field method or property". The error comes from the if statements. Any suggestions on how to correct this issue?
Some background info: I have two classes, one called Customer and one called Menu. The Menu is the main class while Customer is the class I reference from.
This is from my Menu class:
int L = 0;
string I = "";
Customer[] members = new Customer[2];
members[0] = new Customer(3242, "JS");
members[1] = new Customer(7654, "BJ");
Console.Write("\nWhat is your Loyalty ID #: ");
L =Convert.ToInt32(Console.ReadLine());
Console.Write("\nWhat is your first and last name initials: ");
I = Console.ReadLine();
if (L==Customer.GetId())
{
if (I == Customer.GetInitials())
{
Console.WriteLine("It matches");
}
}
else
{
Console.WriteLine("NO match");
}
Console.ReadKey();
}
}
}
This from my Customer class
private int id;
private string initials;
public Customer ()
{
}
public Customer(int id, string initials)
{
SetId(id);
SetInitials(initials);
}
public int GetId()
{
return id;
}
public void SetId(int newId)
{
id = newId;
}
public string GetInitials()
{
return initials;
}
public void SetInitials(string newInitials)
{
initials = newInitials;
}
The error means exactly what it says. You can't access the GetId() function of Customer by calling Customer.GetId() because GetId() only works on an instance of Customer, not directly through the Customer class.
Customer.GetId(); //this doesn't work
Customer myCustomer=new Customer(); myCustomer.GetId(); //this works
To check the user's input against your array of inputs, you need to iterate through the array (or alternatively, use Linq).
I'm going to use a generic list, because there's not really a good reason to use arrays in most cases.
List<Customer> customers=new List<Customer>();
Customers.Add();//call this to add to the customers list.
foreach(var c in customers)
{
if(c.GetId() == inputId)
{
//match!
}
else
{
//not a match
}
}
You can also improve your Customer class by using properties, or auto properties (which doesn't need a backing field). Here's an auto property example:
public string Id {get; set;} // notice there's no backing field?
Using the above auto property syntax would allow you do to this:
var customer = new Customer();
string id = customer.Id; // notice there's no parentheses?
Properties and auto properties allow for a cleaner syntax than having to write Java-style separate getters/setters.
Related
Hello I am trying to create a bank application with 3 classes-Bank, Account, Mainprogram. In my Main program i have an option for the user to Add a new bank account. In my bank class i have my attributes, constructor and add account method.
class Bank
{
// Attributes
private List<int> accounts { get; set; }
private int number_of_accounts { get; set; }
//Constructor
public Bank(List<int> accounts, int number_of_accounts)
{
this.accounts= accounts;
this.number_of_accounts = number_of_accounts;
}
public void AddNewAccount(int accountNumber)
{
accounts.Add(accountNumber);
Console.WriteLine("Account with number " + accountNumber+ "has been added!");
}
Inside my Main I have a menu where user can choose 1.Add account where i call my method.
public static bool MainMenu()
{
Bank myBank = new Bank(accounts, 0); <----- Error here,
switch ()
{
case "1":
// Function
Console.WriteLine("Write the account number desired:");
int userInput= Convert.ToInt32(Console.ReadLine());
myBank.AddNewAccount(userInput);
return true;
case "2":
// Function
Line 3 in my MainMenu it says "The name 'accounts' does not exist in the current context".
The problem is that "accounts" doesn't exist, you have not created any variable called accounts yet. To solve the issue do the following:
var accounts = new List<int>();
Bank myBank = new Bank(accounts, 0);
OR
Bank myBank = new Bank(new List<int>(), 0);
You can just use default constructor in your class, like this :
class Bank
{
public Bank()
{
this.accounts = new List<int>();
this.number_of_accounts = 0;
}
... rest of code (from your original question)
}
You must pay attention to some things:
Usually private is used to fields, not for properties. You have full control of your private fields, so usually you don't define as a private properties.
private readonly List<int> accounts;
private int number_of_accounts;
Also, number_of_accounts is redundant. It's accounts.Count. So it's better use accounts.Count and avoid problems if you forget update number_of_accounts when you modify accounts.
number_of_accounts must be public (and a property instead of a field because is public) and only with get (without set because you can't change the size directly, you do that inserting or removing values).
public int number_of_accounts => accounts.Count;
You don't need a constructor with a list of accounts. Simply create the list. Later, with methods like AddNewAccount, you add elements.
public Bank()
{
this.accounts= new List<int>();
}
You can have a constructor with an initial list of values if you want. But avoid use that list because outside, your code can modify the list and it's better that your class have all control about their fields.
public Bank(List<int> accounts)
{
this.accounts= new List<int>();
this.accounts.AddRange(accounts);
}
I am new to C# and trying to solve some simple tasks and I find my self stuck in a methode that is supposed to get the name of the next customer from right on the list:
The task:
I am given is a directed graph of Customers, where one Customer has exactly one reference to the next Customer or null if it is the last Customer. An example of such a graph can be seen in the diagram below.
Given such a graph, I need to find the customer int numberFromRight nodes from right in the graph by implementing the IFinder interface.
Here is the code I have been working on
class Program
{
static void Main(string[] args)
{
var currentCustomer = Customers
.Create("Kim")
.Previous("Hans")
.Previous("Ole")
.Previous("Peter");
while (currentCustomer != null)
{
if (currentCustomer.Next != null)
Console.Write(currentCustomer.Person + " -> ");
else
Console.WriteLine(currentCustomer.Person);
currentCustomer = currentCustomer.Next;
}
Console.ReadLine();
}
}
Customer class
public class Customers
{
private Customers(Customers next, string person)
{
Next = next;
Person = person;
}
public Customers Next { get; }
public string Person { get; }
public Customers Previous(string person)
{
return new Customers(this, person);
}
public static Customers Create(string person)
{
return new Customers(null, person);
}
}
IFinder interface
public interface IFinder
{
string FromRight(Customers customers, int numberFromRight);
}
I want to write my answer in this method and in example is in the graph below the result for FromRight(peter, 3) is Ole.:
public class Finder : IFinder
{
public string FromRight(Customers customers, int numberFromRight)
{
return name;
}
}
Simple solution without recursion:
public class Finder : IFinder
{
public string FromRight(Customers customers, int numberFromRight)
{
return Unwind(customers).Reverse().Skip(numberFromRight - 1).FirstOrDefault()?.Person;
}
private static IEnumerable<Customers> Unwind(Customers customers)
{
while (customers != null)
{
yield return customers;
customers = customers.Next;
}
}
}
The task: I am given is a directed graph of Customers, where one Customer has exactly one reference to the next Customer or null if it is the last Customer.
So basically what you have in memory is a linked list. While they have some advantages, they are pretty rarely used outside of tree structures exactly because they are a pain to itterate or random access over.
I want to write my answer in this methode and in example is in the
graph below the result for FromRight(peter, 3) is Ole.:
This is recursion, with the number being the recursion depth. Something like this:
public string FromRight(Customers customers, int numberFromRight)
{
if(numberFromRight <= 0)
return customers.Name;
else
return FromRight(customer.Next, (numberFromRight-1));
}
I might have a off-by-one error in this. But those buggers are everywhere. And if forget the null check of course. But it should get you into the right direction at least.
You haven't really showed us what you have tried so far here, just giving us the assignment.
So here's the theorical answer :
Use recursion with the following :
if the next customer doesn't exist, you're at the end of the list, therefore you can return a value straight ahead.
if the next customer does exist, then the answer is the next customer's answer plus one.
first of all congrats for the web, this is my first question but I have found a lot of answer before here.
Here my problem: I have to take some data from an excel file and print them off in a file. Until here everything is ok. But depending on the order of the file list, I take the data in one or another order. My proposal is after all the data have been taken from the excel, to sort those data by the date of the bill (one of the elements of the data). I am describing my classes below.
I have my Bill class:
class Bill
{
private string billNumber;
private string billDate;
private DateTime date;
private string from;
private string to;
private string billCost;
private string power1;
private string power2;
private string power3;
private string power4;
private string power5;
private string power6;
private string contractNumber;
}
And this is my Contract Class:
class Contract
{
private List<Bill> billList;
private Dictionary<double, Bill> billsDictionary;
private double contractNumber;
}
After in my program I have a List<Contract>.
I would like to sort the List<Bill> of the Contract class by the date, to be able to print the bill in the correct order, but I have not been able to find any solution to order them.
Thanks in advance.
Greetings.
There are two solutions. First you need to expose property that can be used to sort.
public class Bill
{
// ... rest of your code
public DateTime Date
{
get
{
return this.date;
}
}
}
1) You can use List's Sort with passed comparer (msdn):
public class Comp : IComparer<Bill>
{
public int Compare(Bill x, Bill y)
{
// remember to handle null values first (x or y or both are nulls)
return x.Date.CompareTo(y.Date);
}
}
then:
billList.Sort(new Comp());
Keep in mind: if you declare Comp as nested class of Bill you won't have to add property Date. You will be able to see private fields of Bill and use it for comparsion..
2) You can use linq (it creates new instance of List):
billList = billList.OrderBy(bill => bill.Date).ToList();
You should be able to do that using linq like q = q.OrderBy(a => a.ColumnName) but you may want to check the access modifiers of your properties, being private you won't be able to access them from the outside.
Here's a simple example on ordering with Linq:
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void OrderByEx1()
{
Pet[] pets = { new Pet { Name="Barley", Age=8 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=1 } };
IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
foreach (Pet pet in query)
{
Console.WriteLine("{0} - {1}", pet.Name, pet.Age);
}
}
/*
This code produces the following output:
Whiskers - 1
Boots - 4
Barley - 8
*/
Notice how the properties of the class are public so you can access them from anywhere in the code.
More info on sorting can be found here.
In one place i am using the list of string in that case the i am able to change the value of the string as code given below,
foreach(string item in itemlist.ToList())
{
item = someValue; //I am able to do this
}
But for object of class i am not able to alter the members value of the object the code is as below,
public class StudentDTO
{
string name;
int rollNo;
}
studentDTOList=GetDataFromDatabase();
foreach(StudentDTO student in studentDTOList.ToList())
{
student = ChangeName(student); //Not working
}
private StudentDTO ChangeName(StudentDTO studentDTO)
{
studentDTO.name = SomeName;
return studentDTO;
}
Error is : Can not assign because it's iteration variable
You cannot change the iteration variable of a foreach-loop, but you can change members of the iteration variable. Therefore change the ChangeName method to
private void ChangeName(StudentDTO studentDTO)
{
studentDTO.name = SomeName;
}
Note that studentDTO is a reference type. Therefore there is no need to return the changed student. What the ChangeName method gets, is not a copy of the student but a reference to the unique student object. The iteration variable and the studentDTOList both reference the same student object as does the studentDTO parameter of the method.
And change the loop to
foreach(StudentDTO student in studentDTOList)
{
ChangeName(student);
}
However, methods like ChangeName are unusual. The way to go is to encapsulate the field in a property
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
You can then change the loop to
foreach(StudentDTO student in studentDTOList)
{
student.Name = SomeName;
}
EDIT
In a comment you say that you have to change many fields. In that case it would be okay to have a method UpdateStudent that would do all the changes; however I still would keep the properties.
If there is no additional logic in the properties besides passing through a value, you can replace them by the handy auto-implemented properties.
public string Name { get; set; }
In that case you would have to drop the field name.
You're not actually changing the object that you're referring to anyway, so you can just use:
foreach (StudentDTO student in studentDTOList)
{
student.name = SomeName;
}
Or still call a method:
foreach (StudentDTO student in studentDTOList)
{
ChangeStudent(student);
}
In both cases, the code doesn't change the value of the iteration variable (student) so it's okay.
But your original example doesn't compile anyway - an iteration variable introduced by a foreach loop is read-only.
Instead of Foreach, I used For loop, this way I also get the Index that is needed to be changed, Then I call a function, In which I pass the Data to be Changed as well as the index to be changed from:
for(int i = 0; i< myList.Count; i++)
{
if(mylist[i] == otherData)
{
//call the function
ChangeData(otherData, i);
}
}
public void ChangeData(DataType DataToChangeInto, int i)
{
mylist[i] = DataToChangeInto;
}
I am looking for easy way to store the output of the method in some sort of variable so that it can be used by another class.
For example:
partial class Form1 {
public string orderNumber() {
string ord="ORD"+get_next_id()+DateTime.Now.Year;
return ord;
}
}
In an instance of Form1 user enter the purchase details such as name, address... and when user clicks add entry button, the details is saved in the database with ordernumber generated by above code. In meantime when user click add entry, it kills the current form and bring up the another form which uses the ordernumber generated earlier. When I do like
Form1 m=new Form1();
and do something like(following is pseudo code)
m.orderNumber=string orderNUm.
It generates different order number which I don't want. I want to use the ordernumber that was saved in the database by the Form1.
I want to store that ord somewhere so that I can pass it to another class.
Another class can use the result simply by calling the method itself:
public class A
{
public string orderNumber()
{
string ord = "ORD" + get_next_id() + DateTime.Now.Year;
return ord;
}
}
public class B
{
public void DoSomeWork()
{
A a = new A();
string result = a.orderNumber();
}
}
The notion of "storing it somewhere" feels like the concept of a global variable. While one can accomplish essentially the same thing, that is to be discouraged as that does not represent object oriented design principals.
Just to understand how you could do that in C# (you should not do this), you could do:
static public SharedStorage
{
public string OrderNumber { get; set; }
}
// Somewhere in your code
SharedStorage.OrderNumber = a.orderNumber();
// Somewhere else in your code
string orderNumber = SharedStorage.OrderNumber;
If you want to set an order number on an instance once and then use it going forward, you could put the logic in the constructor:
public class A
{
public string OrderNumber { get; private set; }
public A()
{
OrderNumber = "ORD" + get_next_id() + DateTime.Now.Year;
}
}
// Somewhere else in your code
A a = new A();
string orderNumber = a.OrderNumber;
This is fairly basic stuff, but add this to the top of the class:
public string OrderCode;
Next add OrderCode = ord; above the return ord; line
Now whenever someone needs the ordercode they just make a call to <YourClass>.OrderCode
However, they could just call the method itself to get the order number as it is public.
PS: the orderNumber method doesn't follow c# conventions. a) it should be properly capitalized (OrderNumber) and b) a more meaningful name would be GetOrderNumber