Accessing properties/fields within functions and event handlers in c# - c#

I have a dictionary that is declared as a property so that I can access it within other functions and event handlers but seeing as I'm new to c# I can't figure out how to do this properly
Declaring the dictionary
Dictionary<string, int> occurrenceDictionary { get; set; }
I have two functions. The first functionOne turns a list of words into a dictionary<string, int> where string is a word, and int is the number of times that word occurs in the list.
public string functionOne(List<string> myList)
{
foreach (string item in myList)
{
if (!occurrenceDictionary.ContainsKey(item))
{
occurrenceDictionary.Add(item, 1);
}
else
{
occurrenceDictionary[item]++;
}
}
return maxKey;
}
The second function compares user input wordSearch.Text to this dictionary occurenceDictionary and if they match, then the user will be told how many times this word occurs (the keys are the words, the values are the amount of occurrences).
public int word_search(Dictionary<string, int> myDict)
{
if(myDict != null)
{
if (myDict.ContainsKey(wordSearch.Text))
{
...
}
else
{
...
}
}
else
{
...
}
}
Now I have an event listener that is waiting for the user to click the Search button. This is the part I'm having the most trouble with, I don't know how to call my word_search function properly inside the event handler, because the way I have it at the moment, I always get a NullReferenceException and it says to fix it I have to add
if(occurencesDictionary != null) ... But adding this to functionOne doesn't make sense to me because I want the items to be added to the dictionary regardless of whether its empty or not because functionOne is populating the dictionary. So I'm not sure how else to get around this problem
If anyone could tell me what I'm doing wrong or perhaps show me an easier method that would be helpful

... But adding this to functionOne doesn't make sense to me because I want the items to be added to the dictionary regardless of whether its empty or not because functionOne is populating the dictionary.
occurencesDictionary is not empty, It's not even initialized.
You will have do first initialize it before using it.
Either you do it in the constructor or by property initializer:
Dictionary<string, int> occurrenceDictionary { get; set; } = new Dictionary<string, int>();

You only declared but never initialized (with new) your hash variable so it is always null.

You need public Dictionary occurrenceDictionary = new Dictionary();
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Dictionary<string, int> occurrenceDictionary = new Dictionary<string, int>();
public string functionOne(List<string> myList)
{
string maxKey = "";
foreach (string item in myList)
{
if (!occurrenceDictionary.ContainsKey(item))
{
occurrenceDictionary.Add(item, 1);
}
else
{
occurrenceDictionary[item]++;
}
}
return maxKey;
}
public int word_search(Dictionary<string, int> myDict)
{
if(myDict != null)
{
if (myDict.ContainsKey(wordSearch.Text))
{
}
else
{
}
}
else
{
}
return 1;
}
private void buttonSearch_Click(object sender, EventArgs e)
{
occurrenceDictionary.Add("hello", 1);
}
}
}

Related

Printing out the list of nodes to the console

using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
//Step 1: Get string from user
//Step 2: Find out how many times each character in the string repeats
//Step 3: find the two characters that repeat the least adding their frequency and add them together with the sum of their frequencies
//step 4: Add this new sum back into the list, wherever it will now go, higher up
//step 5: repeat theses steps, until you have a huffman tree!
namespace HuffmanTree
{
class Program
{
static void Main(string[] args)
{
HuffmanTree.GetValue();
}
}
class HuffmanTree
{
public static void GetValue()
{
Console.WriteLine("Write a string to be encoded"); //Here we are asking the user to input a string
string encodeme = Console.ReadLine(); // here the user inputs their string, which gets declared as the variable "encodeme"
Dictionary<char, int> timesRepeated = new Dictionary<char, int>();
List<Node> HuffmanNodes = new List<Node>();
foreach (char ch in encodeme.Replace(" ", string.Empty))
{
if (timesRepeated.ContainsKey(ch))
{
timesRepeated[ch] = timesRepeated[ch] + 1;
}
else
{
timesRepeated.Add(ch, 1);
}
}
foreach (KeyValuePair<char, int> item in timesRepeated.OrderByDescending(i => i.Value))
{
char key = item.Key;
int count = item.Value;
Console.WriteLine(key.ToString() + " : " + count.ToString());
HuffmanNodes.Add(new Node());
}
Console.WriteLine(HuffmanNodes(node));
}
public class Node //These are going to be the intialisation of our nodes
{
public char Symbol { get; set; }
public int Frequency { get; set; }
public Node Right { get; set; }
public Node Left { get; set; }
}
}
}
I am trying to Console.Write my Huffman tree node list so I can see what is going on. Printing Console.WriteLine(HuffmanNodes(node)); doesn't seem to work. I have tried printing several different ways such as with [i] and it just does not seem to work. This is for debugging, so I can see whats going on with each individual step.
You are trying to invoke HuffmanNodes like a method when, because it is a List<>, you'll need to enumerate it...
foreach (Node node in HuffmanNodes)
{
Console.WriteLine($"Symbol: {node.Symbol}, Frequency: {node.Frequency}");
}
...or iterate it...
for (int i = 0; i < HuffmanNodes.Count; i++)
{
Console.WriteLine($"Symbol: {HuffmanNodes[i].Symbol}, Frequency: {HuffmanNodes[i].Frequency}");
}
...to access each Node it contains.
You could also just incorporate the code to display the list in the preceding foreach loop, since that will give you access to the same Nodes in the same order as they're added to the List<>...
foreach (KeyValuePair<char, int> item in timesRepeated.OrderByDescending(i => i.Value))
{
// [snip]
Node node = new Node();
HuffmanNodes.Add(node);
Console.WriteLine($"Symbol: {node.Symbol}, Frequency: {node.Frequency}");
}
Additional notes:
You never set any of the properties of the Node you add to HuffmanNodes.
If you override the ToString() method of the Node class you could build a diagnostic string much the same way as my Console.WriteLine() calls above. This would allow you to print the properties of a Node with simply Console.WriteLine(node);.
It's odd to have a method named GetValue() that doesn't return anything.

Checking list for custom object

If you have made a list of Custom objects is it a must to have to do with Hashcodes if you wanna check that list to see if it contains a object before adding it, I mean so that you do not get duplicates in the list or is there an easier way basically I want to use the contains method on a custom object list to see if the object I want to add already exists in the list and if there then is an easier way then to have to deal with hashcodes?
This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataConverter.Objects;
namespace DataConverter.Converters
{
class CategoryConverter
{
private Category category;
private SubCategory subCategory;
private ExcellObj excellObj;
public CategoryConverter(string path)
{
excellObj = new ExcellObj(path);
}
public List<Category> getCategoryListExcel()
{
List<Category> categories = new List<Category>();
List<string> ColumnNames = new List<string> { "Group1", "Group1Descr" };
List<int> CorrectColumn = new List<int>();
for(int i = 0; i < ColumnNames.Count; i++)
{
CorrectColumn.Add(excellObj.findColumn(ColumnNames[i]));
}
for(int i = 2; i < excellObj.allRows; i++)
{
categories.Add(category = new Category(excellObj.getValuesFromCell(i, CorrectColumn[1]), excellObj.getValuesFromCell(i, CorrectColumn[0]), "Home"));
}
return categories;
}
public List<List<SubCategory>> getSubCategory()
{
List<SubCategory> subCategories1 = new List<SubCategory>();
List<SubCategory> subCategories2 = new List<SubCategory>();
List<List<SubCategory>> subCategoriesList = new List<List<SubCategory>>();
List<string> ColumnNamesSubCategory1 = new List<string> { "Group2", "Group2Descr" };
List<string> ColumnNamesSubCategory2 = new List<string> { "Group3", "Group3Desc" };
List<int> CorrectColumn1 = new List<int>();
List<int> CorrectColumn2 = new List<int>();
for(int i = 0; i < ColumnNamesSubCategory1.Count; i++)
{
CorrectColumn1.Add(excellObj.findColumn(ColumnNamesSubCategory1[i]));
CorrectColumn2.Add(excellObj.findColumn(ColumnNamesSubCategory2[i]));
}
for(int i = 1; i < excellObj.allRows; i++)
{
subCategories1.Add(subCategory = new SubCategory(excellObj.getValuesFromCell(i, CorrectColumn1[1]),excellObj.getValuesFromCell(i,CorrectColumn1[0]), "Home"));
subCategories2.Add(subCategory = new SubCategory(excellObj.getValuesFromCell(i,CorrectColumn2[1]), excellObj.getValuesFromCell(i,CorrectColumn2[0]), "Home"));
}
subCategoriesList.Add(subCategories1);
subCategoriesList.Add(subCategories2);
return subCategoriesList;
}
public void finnishedUsingExcel()
{
excellObj.CloseApplication();
}
}
}
and what i whant to happen is that i whant to run a
if(categories.Contains(category) == false){
categories.add(category)
}
i do not understand this part in the documentation?
public Person(string lastName, string ssn)
{
if (Regex.IsMatch(ssn, #"\d{9}"))
uniqueSsn = $"{ssn.Substring(0, 3)}-{ssn.Substring(3, 2)}-{ssn.Substring(5, 4)}";
else if (Regex.IsMatch(ssn, #"\d{3}-\d{2}-\d{4}"))
uniqueSsn = ssn;
else
throw new FormatException("The social security number has an invalid format.");
this.LastName = lastName;
}
Assuming you have a code like this:
List<CustomObject> listOfCustomObjects = new List<CustomObject>();
Solution 1
If so, you can use listOfCustomObjects.Contains(customObject) to find out if customObject is in listOfCustomObjects. You should add using System.Linq; to the top of your code in order to use this method.
Solution 2
Another way to not have duplicates in your list is basically not using a List. You can use HashSet instead. With this method, duplicate objects won't be added to your list automatically. HashSet is also in LINQ Library, so you should add the line using System.Linq; for this solution too. Here's an example how to create a new HashSet with your CustomObject class:
HashSet<CustomObject> setOfCustomObjects = new HashSet<CustomObject>();
You really should have your class implement IEquatable if it's reasonable to do so and you're going to check for equality with any frequency, just so it does not bite you. The "Contains" method will work, but only to test that the exact same instance is present, not necessarily one that just shares matching properties. Consider the following code:
class Program
{
static void Main(string[] args)
{
var classInstance = new MySampleClass("testA", "testB");
var classList = new List<MySampleClass>();
classList.Add(classInstance);
if (classList.Contains(new MySampleClass("testA", "testB")))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
if (classList.Contains(classInstance))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
}
}
public class MySampleClass
{
public string SampleProperty1 { get; set; }
public string SampleProperty2 { get; set; }
public MySampleClass(string sampleProperty1, string sampleProperty2)
{
SampleProperty1 = sampleProperty1;
SampleProperty2 = sampleProperty2;
}
}
Even though we're checking for the presence of the class that has the exact same values as the one we previously added, they're still separate instances and you'll end up with duplicates in your list.
An alternative in the very limited case would be to use a LINQ method to check whether the list already contains an entry with a property that can be compared, such as an int ID or something:
yourList.Any(item => item.Id.Equals(otherItem.Id));
Again, if it's more than a one off, implement it the right way with IEquatable. See Microsoft's documentation

Populate Combobox from a list

Newb here,
I'm currently working on a form which has a combo box, which will show several Charlie Brown TV specials which you can click on to select and see a description of, rating, runtime, etc. I'm close but I'm not there in terms of populating the combo box and i'm hoping for some help and guidance. I have looked at several things others have done but i'm not knowledgeable enough to deduce the answers from what i've been able to see so far.
Right now i'm trying too:
1. get the listings from your load method
2. loop through them
3. Access my combo box to populate the box with the times from the listing.
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;//Used for Sting.ToUpperCase...
using System.Threading;
using System.Threading.Tasks;// Needed for Streaming...
using System.IO;// Needed for Streaming...
namespace a100___GUI___VideoStoreSelections
{
public partial class FormMovieLookUp : Form
{
private const String FILE_NAME = "txt_movieDescriptions.txt";//connect to text file in debug
private List<Listing> films { get; set; }
public FormMovieLookUp()
{
InitializeComponent();
}
private void cmbMovieListingBox_SelectedIndexChanged(object sender, EventArgs e)
{
txtTitleBox.Text = cmbMovieListingBox.SelectedItem.ToString();
}
//ToolBox -- my program specific tools
public List<Listing> LoadListings()//load movie descriptions as list
{
StreamReader fileIn = new StreamReader(FILE_NAME);
List<Listing> entries = new List<Listing>();
//loop through every line of the file
while (!fileIn.EndOfStream)
{
String line = fileIn.ReadLine();
String[] pieces = line.Split(':');
if (pieces.Length < 4) continue;//error handling - set to length of text items
Listing myListing = new Listing(pieces[0], pieces[1], pieces[2], pieces[3]);
entries.Add(myListing);
}
fileIn.Close();
return entries;
}
private void FormMovieLookUp_Load_1(object sender, EventArgs e)
{
films = LoadListings();
foreach (Listing film in films)
{
Console.WriteLine(film);
cmbMovieListingBox.Items.Add(film.GetFilmTitle());
}
}
}
}
Listing.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace a100___GUI___VideoStoreSelections
{
public class Listing
{
private String filmTitle;
private String description;
private String filmRunTime;
private String filmRating;
public Listing(String filmTitle, String description, String filmRunTime, String filmRating)
{
this.filmTitle = filmTitle;
this.description = description;
this.filmRunTime = filmRunTime;
this.filmRating = filmRating;
}
public String GetFilmTitle() { return filmTitle; }
public String GetDescription() { return description; }
public String GetFilmRunTime() { return filmRunTime; }
public String GetFilmRating() { return filmRating; }
}
}
So this is what i'm trying to do to populate my combo box. Any help is thankfully received.
I would hold List<Listing> at the class level so you can access it when a user clicks on it. I would also throw this on it's own thread and not directly in the Load event. If it's a long process you will hang the ui.
private List<Listing> films { get; set; }
Load
films = LoadListings();
foreach (Listing film in films)
{
cmbMovieListingBox.Items.Add(film.GetFilmTitle());
}
When the user selects the item
Listing film = films.Where(f => f.GetFilmTitle().Equals(cmbMovieListingBox.SelectedValue)).FistOrDefault();
if (film != null)
{
//do work
}
if you are asking what i think you are asking, you need something like this in your form load:
foreach(Listing listing in LoadListings()){
cmbMovieListingBox.Items.Add(listing.GetFilmTitle());
}
Remove the {get; set;} from the list declaration. It's not needed there.
Define your class like this:
public class Listing
{
private String filmTitle {get; set;}
private String description {get; set;};
…
}
On the form load event set the ComboBox DisplayMember and ValueMember to "filmTitle"
cmbMovieListingBox.DisplayMember = "filmTitle";
cmbMovieListingBox.ValueMember = "filmTitle"
Finally, you must set the DataSource of the ComboBox to the list
cmbMovieListingBox.DataSource = films;
And there you have it. The rest of your code should function now.
There's one issue with visual controls updating (such as ComboBox etc): you'd rather prevent them from re-painting at each data change (at each item addition in your case):
cmbMovieListingBox.BeginUpdate(); // <- Stop painting
try {
// Adding new items into the cmbMovieListingBox
foreach(var item in LoadListings())
cmbMovieListingBox.Items.Add(item.GetFilmTitle());
finally {
cmbMovieListingBox.EndUpdate(); // <- Finally, repaint if required
}
A line of the code of Tsukasa doesn't work because it is written FistOrDefault() instead of FirstOrDefault()
Listing film = films.Where(f => f.GetFilmTitle().Equals(cmbMovieListingBox.SelectedValue)).**First**OrDefault();
Sorry I don't have enough point to just add a comment...
Maybe it will help somebody. But in my situation I had to use cmbMovieListingBox.Text instead of cmbMovieListingBox.SelectedValue (like #Tsukasa example):
Listing film = films.Where(f => f.GetFilmTitle().Equals(cmbMovieListingBox.Text)).FirstOrDefault();
if (film != null)
{
//do work
}
And also FirstOrDefault() instead of FistOrDefault().
Hope it helps to someone
that what i did to my Code
int Count;
foreach(String i in Languages)
{
LangComboBox.Items.Add(Languages[Count]);
Count++;
}

c# program of Indexers

there is an error in this program.can anyone fix that?
Error is :TempRecord already defines a member called 'this' with the same parameters value
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication6
{
class TempRecord
{
// Array of temperature values
private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F,
61.3F, 65.9F, 62.1F, 59.2F, 57.5F };
private int[] d= new int[10]{4,5,5,4,4,43,2,2,5,3};
// To enable client code to validate input
// when accessing your indexer.
//public int Length
//{
// get { return temps.Length; }
//}
// Indexer declaration.
// If index is out of range, the temps array will throw the exception.
public float this[int index]
{
get
{
return temps[index];
}
set
{
temps[index] = value;
}
}
public int this[int index]//error:TempRecord already defines a member called 'this' with the same parameters value
{
get
{
return d[index];
}
set
{
d[index] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
TempRecord tempRecord = new TempRecord();
// Use the indexer's set accessor
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;
// Use the indexer's get accessor
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
}
Console.WriteLine(tempRecord[2]);
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
}
You have two members named this, that take the same parameters. That's not allowed in C# (or other .Net languages, as far as I'm aware).
You'd think you'd be able to do this if both members return different types, as yours do. But that would present the compiler with ambiguity. Which member would be called if you had code like this?
object x = tempRecord[3];
Make one or both indexers a method.
What you're trying to do is have 2 indexers with the same parameters and different return types. This is not legal in C#. You'll need to move at least one of them into a function
public int GetD(int index) {
return d[index];
}
public void SetD(int index, int value) {
d[index] = value;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication6
{
class TempRecord
{
// Array of temperature values
private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F, 61.3F, 65.9F, 62.1F, 59.2F, 57.5F }; private int[] d = new int[10] { 4, 5, 5, 4, 4, 43, 2, 2, 5, 3 };
public int Length //
{
get { return temps.Length; }
}
public float this[int index]
{
get { return temps[index]; }
set { temps[index] = value; }
}
}
class Program
{
static void Main(string[] args)
{
TempRecord tempRecord = new TempRecord();
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
}
Console.WriteLine(tempRecord[2]);
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
}
If you are trying some concept similar to overloading of functions, I'd like to say it never works with just a change in return type. Similar is the case of data members, where you have tried to use this with the same arguments but different return types.
The best method would be however (even for readability sake) making separate functions for the exclusive events that are being performed above.
I deleted the second data member above, replace it with the something like the foll. I think you better use temprecord.d[index Value] to access & use the member d from main.
public int d[int index]
{
get
{
return d[index];
}
set
{
d[index] = value;
}
}

Adding Items to ListBox, RadioList, Combobox using reflection

I'm trying to add items to a listbox,combobox, radiolist using reflection. The code I have at the moment is as follows:
public static Control ConfigureControl(Control control, ControlConfig ctrlconf)
{
if (control is TextBox)
{
// ...
}
else
{
// get the properties of the control
//
Type controlType = control.GetType();
PropertyInfo[] controlPropertiesArray = controlType.GetProperties();
foreach (PropertyInfo controlProperty in controlPropertiesArray)
{
if (controlProperty.Name == "Items" && controlProperty.PropertyType == typeof(ListItemCollection))
{
object instance = Activator.CreateInstance(controlProperty.PropertyType);
MethodInfo addMethod = controlProperty.PropertyType.GetMethod("Add", new Type[] { typeof(ListItem)} );
List<string> popValues = new List<string>(ctrlconf.PopulatedValues.Split(';'));
if (popValues.Count.Equals(0))
{
throw new ArgumentException("No values found for control");
}
else
{
foreach (string val in popValues)
{
addMethod.Invoke(instance, new object[] { new ListItem(val, val) });
}
}
}
}
}
return control;
}
The code above populates the listitemcollection which I have instantiated using Activator.CreateInstance, however I'm not sure how to add it to the ListBox.
Any help would be great.
Thanks,
Peter
You don't need or want to instantiate the collection object: that's already done by the control. Instead, you need to get the existing collection object, then add to that:
if (controlProperty.Name == "Items" && controlProperty.PropertyType == typeof(ListItemCollection))
{
object instance = controlProperty.GetValue(control, null);
// ... now go on and add to the collection ...
}
However, as others have noted, this may not be the best way to approach the problem. Instead, consider implementing adapter or strategy for the various controls you want to support e.g. RadioButtonListItemAdder, ListControlItemAdder, etc., which all conform to a common interface. Each type of XxxItemAdder can implement its own strongly-typed code, suitable for the type of control it's responsible for adding items to. This might look something like the following:
public interface IItemAdder
{
void AddItem(string value);
}
public class ListControlItemAdder : IItemAdder
{
private readonly ListControl _listControl;
public ListControlItemAdder(ListControl listControl)
{
_listControl = listControl;
}
public void AddItem(string value)
{
_listControl.Items.Add(value); // or new ListItem(value, value) per your original code
}
}
public class RadioButtonListItemAdder : IItemAdder
{
// ...
public void AddItem(string value)
{
// do whatever you have to do to add an item to a list of RadioButtons
}
}
public static IItemAdder CreateItemAdderFor(Control control)
{
if (control is ListControl)
return new ListControlItemAdder((ListControl)control);
else if (control is RadioButtonList)
return new RadioButtonListItemAdder((RadioButtonList)control);
// etc. to cover other cases
}
public static Control ConfigureControl(Control control, ...)
{
// ... omitting code that looks like your existing code ...
IItemAdder itemAdder = CreateItemAdderFor(control);
foreach (string val in popValues)
itemAdder.AddItem(val);
}
This is a really untidy implementation but hopefully gives you the idea of how you can separate out each of the individual control-specific implementations into small, nicely separated classes.

Categories