Am I using Lists correctly? - c#

In my page load, am I calling ReturnStuff() once or three times?
If I am calling it three times, is there a more efficient way to do this?
protected void Page_Load(object sender, EventArgs e)
{
string thing1 = ReturnStuff(username,password)[0];
string thing2 = ReturnStuff(username, password)[1];
string thing3 = ReturnStuff(username, password)[2];
}
public static List<string> ReturnStuff(string foo, string bar)
{
// Create a list to contain the attributes
List<string> Stuff = new List<string>();
// Some process that determines strings values based on supplied parameters
Stuff.Add(fn);
Stuff.Add(ln);
Stuff.Add(em);
return Stuff;
}

You're calling it three times. Here is a more efficient way:
protected void Page_Load(object sender, EventArgs e)
{
var stuff = ReturnStuff(username,password);
string thing1 = stuff[0];
string thing2 = stuff[1];
string thing3 = stuff[2];
}
But more than that, if you have a first name, last name, and e-mail, I would write a function that returns an object composing a first name, last name, and e-mail:
public class User
{
public string LastName {get;set;}
public string FirstName {get;set;}
public string EMail {get;set;}
}
public static User GetUser(string username, string password)
{
// Some process that determines strings values based on supplied parameters
return new User() {FirstName=fn, LastName=ln, EMail=em};
}
protected void Page_Load(object sender, EventArgs e)
{
var user = GetUser(username,password);
}

3 times.
following code will help you realize. go to Main function and call func() from there.
class howmanytimescallingafunction
{
public static int i = 0;
public List<string> fun()
{
List<string> list = new List<string> { "A", "B", "C" };
i++;
return list;
}
public void func()
{
Console.WriteLine(fun()[0]);
Console.WriteLine(i);
Console.WriteLine(fun()[1]);
Console.WriteLine(i);
Console.WriteLine(fun()[2]);
Console.WriteLine(i);
}
}
You should call that function once, get the returned value in a local List<> variable and then access using the variable. like this:
List<string> list = function-that-returns-List<string>();
list[0]; //Do whatever with list now.

You're calling it 3 times. Call it once and save the results to a variable, then you can work with that variable.
Try this:
var stuff = ReturnStuff(username,password);
string thing1 = stuff[0];
string thing2 = stuff[1];
string thing3 = stuff[2];

Related

How do I obtain a parameter of all objects from a class constructor in c#

I am making a very basic sort of online ATM app using c#.NET. Bascically i have made a class called account and have used a constructor to store the accounts of customers, making them objects of the class. These customers are to enter a pin to login. The customer's pin is one of the parameter of the customer object and i have been trying to make a loop that will loop through all the individual customers and identify which account the pin belongs to.
class Account
{
public string customerName;
public string pin;
public int balance;
public Account(string accCustomerName, string accPin, int accBalance)
{
customerName = accCustomerName;
pin = accPin;
balance = accBalance;
}
}
private void Form1_Load(object sender, EventArgs e)
{
Account acc1 = new Account("Henry_Adobe", "2316", 10000);
Account acc2 = new Account("Patrick_Boka", "3198", 15000);
Account acc3 = new Account("Fred_Simp", "8768", 20000);
Account acc4 = new Account("Derek_Black", "7645", 25000);
if (txtInput.Text == acc1.pin)
{
MessageBox.Show("Login Succesful!");
}
}
I have managed to access the pin by stating the name of a specific name of each object(acc1.pin) but this is not efficient as it requires me to enter the name of very object. Is there a way in which i could easily access the parameters of all the accounts?
I'll take a you a step further, since an ATM app that forgets the last balance each time it runs isn't very useful.
Let's start with Account class:
class Account
{
public string CustomerName {get;set;};
public string PIN {get;set;};
public decimal Balance {get;set;};
public Account(string customerName, string Pin, decimal balance)
{
CustomerName = customerName;
PIN = Pin;
Balance = balance;
}
public static IList<Account> Accounts {get;private set;} = new List<Account>();
public static void ReadAccounts(string fileName)
{
using var rdr = new Microsoft.VisualBasic.FileIO.TextFieldParser(AccountsFileName))
{
rdr.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited;
rdr.Delimiters = new string[] {','};
Accounts.Clear();
string[] row = null;
while( (row = rdr.ReadFields()) != null)
{
Accounts.Add(new Account(row[3], row[0], Decimal.Parse(row[1])));
}
}
}
public static void WriteAccounts(string fileName)
{
using (var writer = new StreamWriter(fileName, false))
{
writer.WriteLine("PIN,Balance,CustomerName");
foreach(var acct in Accounts)
{
writer.WriteLine($"{acct.PIN},{acct.Balance},\"{acct.CustomerName}\"");
}
}
}
}
We updated the fields to become properties with meaningful data types, added a static place to the keep the list of accounts, and added methods to read and write from a file. Later on, you'll replace the csv file with a database of some kind, but this will get you started.
Now let's move on to loading the form:
private string AccountsFileName = "AccountsFile.csv";
private void Form1_Load(object sender, EventArgs e)
{
Account.ReadFile(AccountsFileName);
}
But we need to stop there. At the point where a form loads, the user hasn't had a chance to enter any text yet! You need a button, in addition to the textbox, where the user can click to login after they type the pin:
private Account currentAccount = null;
private void btnLogin_Click(object sender, EventArgs e)
{
currentAccount = Account.Accounts.FirstOrDefault(a => a.PIN == txtInput.Text);
if (currentAccount != null)
{
MessageBox.Show("Login successful!");
return;
}
MessageBox.Show("Login failed");
}
And, finally, you need a way to save the file when the program ends. For now I'll just use the Form1_Closing event, but later you'll probably need something different:
private void Form1_Closing(object sender, EventArgs e)
{
Account.WriteAccounts(AccountsFileName);
}
What you're still missing is the ability to show users their balance and allow them to make deposits and withdrawals. Additionally, any ATM worth using will need to show individual transactions, typically stored as two off-setting ledger entries.

static LIST of class returning same value

I have two classes, one contains the value I want to maintain and it is declared as [serializable] since I may want to store the results in a file later.
namespace WindowsFormsApp1
{
[Serializable]
public class Class1
{
string Something = "";
public Class1(string something)
{
Something = something;
}
public Class1()
{
Something = "";
}
public string something
{
get { return Something; }
set { Something = value; }
}
}
}
The second declares a List of this class along with a few access functions
namespace WindowsFormsApp1
{
class Class2
{
public static List<Class1> aClass = new List<Class1>();
public static int cnt = 0;
public void AddStaticString(Class1 aString)
{
aClass.Add(aString);
cnt++;
}
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{
aFullString = aClass[cnt].something;
cnt++;
}
return aFullString;
}
}
}
Now a simple bit of code to add to the LIST and try to extract it
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Class1 aClass = new Class1();
Class2 aSClass = new Class2();
aClass.something = "AAAAA";
aSClass.AddStaticString(aClass);
aClass.something = "BBBBB";
aSClass.AddStaticString(aClass);
aClass.something = "CCCCC";
aSClass.AddStaticString(aClass);
richTextBox1.Text = aSClass.GetAllStrings();
}
}
}
The richTextBox always displays the last item only (CCCCC), even though I can see the proper values being input into the LIST.
Can I not access the members of the LIST with aFullString = aClass[cnt].something; ?
You are just returning the last string from the list in GetAllStrings. Rather you could append it to existing item, or maybe separate them using comma, whatever you want.
For example, you can append those values using simply:
aFullString += aClass[cnt].something + ",";
But that would leave a comma at the end of the string.
Rather, if you need comma separated values, you could just join the strings using LINQ,
public string GetAllStrings()
{
return string.Join(",", aClass.Select(item => item.something));
}
Also, in button1_Click you are adding the same instance of Class1 to the list in Class2. If you need separate instances of the class, you should create new instance before calling AddStaticString:
private void button1_Click(object sender, EventArgs e)
{
Class2 aSClass = new Class2();
Class1 aClass = new Class1();
aClass.something = "AAAAA";
aSClass.AddStaticString(aClass);
aClass = new Class1();
aClass.something = "BBBBB";
aSClass.AddStaticString(aClass);
aClass = new Class1();
aClass.something = "CCCCC";
aSClass.AddStaticString(aClass);
richTextBox1.Text = aSClass.GetAllStrings();
}
You should, but the way you are assigning that aFullString variable will always show the last value of the list.
You should try it like this:
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{ //+ to keep the previous values too
aFullString += aClass[cnt].something;
cnt++;
}
return aFullString;
}
In this method:
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{
aFullString = aClass[cnt].something;
cnt++;
}
return aFullString;
}
You set aFullString to the last collection item's something.
What you want is probably string concatenation. You don't need while loop - for or foreach loop suit better, or even string.Join would be the best option:
public string GetAllStrings()
{
return String.Join(" ", aClass.Select(x => x.something);
}
Please, note that your code has many style and naming errors, unused or useless variables like class members Something and cnt, and doesn't make much sense in general.
You need to follow C# naming conventions and rules to make your code readable and understandable by other developers.

C# return Dictionary

Im trying to write a method that returns a Dictionary, but it seems like it ends up being empty.
Can you find out what I am doing wrong ?
When I click the button to search for a Key, It gives Error: Dictionary contains no Keys.
class Person
{
public int PersNr { get; set; }
public string Name { get; set; }
public string BioPappa { get; set; }
public Adress Adress { get; set; }
public static Dictionary<int, Person> Metod()
{
var dict = new Dictionary<int, Person>();
dict.Add(870603, new Person
{
Name = "Jonathan",
PersNr = 870603,
BioPappa = "Jarmo",
Adress = new Adress
{
Land = "Sverige",
PostNr = 73249,
Stad = "Arboga"
}
});
dict.Add(840615, new Person
{
Name = "Lina",
PersNr = 840615,
BioPappa = "Erik"
});
return dict;
}
namespace WindowsFormsApplication148
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Person.Metod();
var person = myDic[int.Parse(textBoxSok.Text)];
listBox1.Items.Add(person.Name);
listBox1.Items.Add(person.PersNr);
listBox1.Items.Add(person.BioPappa);
listBox1.Items.Add(person.Adress.Stad);
listBox1.Items.Add(person.Adress.PostNr);
listBox1.Items.Add(person.Adress.Land);
}
When you call your method (Please use a more meaningful and less confusing name) you need to receive the result of its work
private void button1_Click(object sender, EventArgs e)
{
Dictionary<int, Person> myDic = person.Metod();
var person = myDic[int.Parse(textBoxSok.Text)];
.......
However you haven't shown all of your code because, as shown in your question the code doesn't compile. I suppose that you have somewhere declared AND INITIALIZED the variable myDic because you need to use it in different parts of your forms. This is somewhat to be analyzed better because the call to Metod reinitializes the local variable myDic to the Dictionary returned by the method call.
private void button1_Click(object sender, EventArgs e)
{
//WRONG
Person.Metod();
You execute a method but do not assign the result to anything.

C# Event Argument passing

Ok, so I have a question regarding the EventArgs that can be passed when an event is triggered. I am designing a small, basic search engine and have a class called Query that contains a method Search. When this method is called, I want to trigger an event which will pass the results to be storred in a variety of cache class instances (SizeBoundedCache and TimeBoundedCache). So I thought the best way to do this would be to use an event.
The delegate is declared like this ->
public delegate void CacheStoreDelegate(object sender, EventArgs e);
The rest of the code within the Query class relevant to this question is here (uses Linq) ->
public event CacheStoreDelegate AddToCache;
public virtual void OnQuery (EventArgs e)
{
if(AddToCache != null)
AddToCache(this, e);
}
public Query()
{
}
public Query(string queryString, OOP5.Provided.QueryOperator op)
{
//Access and set the terms array
this.Terms = OOP5.Provided.QueryUtils.GetTermsFromString(queryString);
this.Operator = op;
}
public static IEnumerable<string> Search (this SearchCore s, IQuery q)
{
// Accept a query and return IEnumerable<string> of
// all document IDs matching that query
if (q.Operator == QueryOperator.Any)
{
var GetAnyMatch = from single_query in q.Terms
group s.Search(single_query)
by s.documents.Keys
into results
where results.Count >= 1
select results[0];
this.OnQuery(GetAnyMatch);
return GetAnyMatch;
}
if (q.Operator == QueryOperator.All)
{
var GetAllMatch = from single_query in q.Terms
group s.Search(single_query)
by s.documents.Keys
into results
where results.Count >= q.Terms.Lengthselect results[0];
this.OnQuery(GetAllMatch);
return GetAllMatch;
}
}
All the cache classes will be notified whenever a search is called and I also need thme to receive the results.
Thanks so much in advance for the help. Also, if there is a more elegant way to do this that I am not thinking of, please chime in. Cheers!
You could create your own EventArgs implementation:
class QueryResultEventArgs : EventArgs
{
public IEnumerable<string> Results { get; private set; }
public QueryResultEventArgs(IEnumerable<string> results)
{
Results = results;
}
}
...
public delegate void CacheStoreDelegate(object sender, QueryResultEventArgs e);
...
this.OnQuery(new QueryResultEventArgs(GetAnyMatch));
Make a class of type CacheStoreEventArgs deriving from eventargs
public class CacheStoreEventArgs:eventargs
{
private IEnumerable<string> Data;//List<string> better
public IEnumerable<string> data
{
get { return Data; }
set { this.Data = value; }
}
public CacheStoreEventArgs(IEnumerable<string> NewData)
{
this.data = NewData;
}
}
then declare the event(use predefined generic one,so no need to declare one)
public event EventHandler<CacheStoreEventArgs> AddToCache;
inside your method search you call your method "On...."
public static IEnumerable<string> Search (this SearchCore s, IQuery q)
{
//after you get query result
CacheStoreEventArgs cs = new CacheStoreEventArgs(queryresultvariablehere);
//and call your method now with the instance of your derived eventargs class
OnQuery(cs);
}
public virtual void OnQuery (CacheStoreEventArgs e)
{
try
{
EventHandler<CacheStoreEventArgs> temp = AddToCache
if( temp != null)
temp(this,e);
}
catch(Exception ex)
{
//exception handling
}
}

How to get a list box to disallow duplicate items?

Bassicly im creating a program that reads information from an xml file into a lisbox and allows the user to transfer items in the list box to another listBox.
But i want to some how disallow multiple items from being imported from one listBox to the other. I thought i can somehow do an experession to check if the String already Exists in the listBox.
The reason i want to do this is because the user can click x amount of times in order to import items and it's unproffesional.
Any Help would be appreciated thank you.
private void button1_Click(object sender, EventArgs e)
{
if (!listBox.Items.Exists) // Random Idea which doesnt work
{
listBox2.Items.Add(listBox1.Items[listBox1.SelectedIndex]);
}
}
private void button1_Click(object sender, EventArgs e)
{
if (!listBox.Items.Exists) // Random Idea which doesnt work
{
listBox2.Items.Add(listBox1.Items[listBox1.SelectedIndex]);
}
}
That will work actually, but you need to use the Contains method. However, you may be missing one crucial point.
What type of items are you using to populate your ListBox? Exists will call .Equals which, by default, uses reference equality. So, if you need to filter based on value, you need to override .Equals for your type and change the semantics.
For example:
class Foo
{
public string Name { get; set; }
public Foo(string name)
{
Name = name;
}
}
class Program
{
static void Main( string[] args )
{
var x = new Foo("ed");
var y = new Foo("ed");
Console.WriteLine(x.Equals(y)); // prints "False"
}
}
However, if we override .Equals to provide value type semantics...
class Foo
{
public string Name { get; set; }
public Foo(string name)
{
Name = name;
}
public override bool Equals(object obj)
{
// error and type checking go here!
return ((Foo)obj).Name == this.Name;
}
// should override GetHashCode as well
}
class Program
{
static void Main( string[] args )
{
var x = new Foo("ed");
var y = new Foo("ed");
Console.WriteLine(x.Equals(y)); // prints "True"
Console.Read();
}
}
And now your call to if(!listBox.Items.Contains(item)) will work as you intended it to. However, if you wish it to continue working you will need to add the item to both listboxes, not just listBox2.
This should do it for you...
private void button1_Click(object sender, EventArgs e)
{
if (!ListBox.Items.Contains(listBox1.SelectedItem)) // Random Idea which doesnt work
{
listBox2.Items.Add(listBox1.SelectedItem);
}
}

Categories

Resources