How to read a List from one class in another - c#

Ok, so in a console application I'm working on, I have a list (myList) in Class01
class Class01
{
public List<string> myList = new List<string>();
public void _addsList()
{
myList.Add("0001Test01");
myList.Add("0002Test02");
myList.Add("0003Test03");
myList.Add("0004Test04");
for (int i = 0; i < myList.Count; i++)
{
Console.WriteLine(myList[i] + ",");
}
}
}
and I need to read that list in Class02
class Class02
{
public void _callList()
{
var class02 = new Class01();
string wits2;
List<string> buffer = new List<string>();
for (int i = 0; i < class02.myList.Count; i++)
{
wits2 = class02.myList[i].Substring(0, 4);
Console.WriteLine(class02.myList[i]);
}
Console.ReadKey();
}
}
The Output of this program should write this to the Console:
0001Test01,
0002Test02,
0003Test03,
0004Test04,
0001
0002
0003
0004
Now I've seen GetList used to do this
public class MyClass {
private List<string> myList = new List<string>();
public List<string> GetList()
{
return myList;
}
}
public class CallingClass {
MyClass myClass = new MyClass();
public void GetList()
{
List<string> calledList = myClass.GetList();
///More code here...
}
}
But I for the life of me can not get this to work. I don't know if I'm missing a namespace or what. I don't even know if GetList works in console application.
So I would really appreciate the help.
Thanks-

Though not totally clear from your question what is not working. But I suspect you need to put values in the list. If you mean it is not displaying anything in the console try this:
var class02 = new Class01();
string wits2;
class02._addsList();
EDIT: after reading your comment, I think this will remedy it:
for (int i = 0; i < class02.myList.Count; i++)
{
wits2 = class02.myList[i].Substring(0, 4);
Console.WriteLine(class02.myList[i]);
buffer.Add(wits2);//Add it to list declared in this function
}
NOTE: If you mean you are getting output when calling _addsList on class object the make sure that you have called this function once before using an object of Class01. From second block of code for Class02 you are not calling _addsList function on object of Class01.

On your Class02:
var class02 = new Class01();
class02._addsList(); //Add this on your declaration
string wits2;
Then change the variable you are passing on your Console.WriteLine:
List<string> buffer = new List<string>();
for (int i = 0; i < class02.myList.Count; i++)
{
wits2 = class02.myList[i].Substring(0, 4);
//Console.WriteLine(class02.myList[i]); //Remove this
Console.WriteLine(wits2); //Use wits2 instead since this is what you get on your Substring
}

I think most important thing you are missing is that your classes are not marked as public
so please add public before class declarations as below
public class Class02
{
......
One more thing, to get your required output, in your class02 you are assigning substring to 'wits' variable but not printing it. You are instead passing value from list to Console.Writeline.
Hope this helps

Thanks to TheVillageIdiot. I got this working now. So thank you. My code looks like this now:
public class Class01
{
public List<string> myList = new List<string>();
public void _addsList()
{
myList.Add("0001Test01");
myList.Add("0002Test02");
myList.Add("0003Test03");
myList.Add("0004Test04");
}
}
class Class02
{
public void _callList()
{
var class01 = new Class01();
class01._addsList(); //<--- Had to add this line
for (int i = 0; i < class01.myList.Count; i++)
{
Console.WriteLine(class01.myList[i] + ",");
}
string wits2;
List<string> buffer = new List<string>();
for (int i = 0; i < class01.myList.Count; i++)
{
wits2 = class01.myList[i].Substring(0, 4);
Console.WriteLine(wits2);
}
Console.ReadKey();
}
}
For toughs who didn't understand the problem, Class02 could not read the List in Class01.
Thanks for the Help!

Related

Using a method made in a parent class in a child class c#

I have two classes:
class ClassOne
{
Stack<int> s = new Stack<int>();
public Stack<int> MakeStack()
{
for (int i = 0; i < 10; i++)
{
s.Push(i);
}
return s;
}
}
class ClassTwo:ClassOne
{
Stack<int> st = MakeStack();
int[] array = new int[2];
private int[] GetFirstTwo()
{
for (int i = 0; i < 1; i++)
{
array[i] = st.Pop();
}
return array;
}
}
but when I am trying to use MakeStack in the child class it gives the error "A field initalizer cannot reference the non-static field, method, or property 'ClassOne.MakeStack'.
I know one fix would be to do everything inside the parent class and make it abstract for when I need to override things inside different child classes, but was hoping there is a way to do what I need without all that as I couldnt find anything helpful when looking into it.
Use the constructor:
class ClassTwo : ClassOne
{
Stack<int> st;
ClassTwo()
{
st = MakeStack();
}
// ...
}
For the why look for example here: Understanding C# field initialization requirements

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

How to override ToString method for List of Lists

I'm pretty new with C# and I'm stuck on one university exercise. I have to sort some elements and them display them by overriden method ToString. And override is problem there. List works with ToString, List of Lists not.
Untill now I've tried to create some easy foreach and put it into overriden method, still, without success. It works only out of method. Asked my professor and he told me, it's because I'm acessing List, not Lista1, or something like that. Like I've said, I'm newbie.
using System;
using System.Collections.Generic;
namespace lista_7
{
class Lista
{
public static Random rand = new Random();
public List<int> nums = new List<int> ();
public Lista(int n)
{
for (int i = 0; i <= n; i++)
{
nums.Add(rand.Next(100));
}
}
public Lista()
{
Random rand = new Random();
for (int i = 0; i <= rand.Next(5); i++)
{
nums.Add(rand.Next(100));
}
}
public override string ToString()
{
String result = "";
foreach (var numbers in nums)
{
result += numbers + " ";
}
return result;
}
}
class Lista1 : Lista, IComparable<Lista1>
{
public Lista1(int n) : base(n) { }
public Lista1() : base() { }
public int CompareTo(Lista1 x)
{
if (x == this) return 0;
else if (x == null) return 1;
for (int i = 0; i < this.nums.Count && i < x.nums.Count; i++)
{
if (this.nums[i] > x.nums[i]) return 1;
else if (this.nums[i] < x.nums[i]) return -1;
}
return x.nums.Count > this.nums.Count ? -1 : 1;
}
}
class Program
{
static void Main(string[] args)
{
List<Lista1> fir = new List<Lista1> {
new Lista1(5),
new Lista1(),
new Lista1(3)
};
foreach (var variable in fir)
{
//Console.Write ( toString )
foreach (var x in variable.nums)
{
Console.Write(x + " ");
}
Console.WriteLine();
}
Console.WriteLine(fir.ToString());
Console.ReadLine();
}
}
}
I would describe errors, but I dont have any. fir.ToString shows System.Collections.Generic.List`1[lista_7.Lista1]
Put your fir.ToString() inside your loop as variable.ToString():
foreach (var variable in fir)
{
Console.WriteLine(variable.ToString());
}
I'm not sure it's a good idea to override ToString() method, I'd rather create an extension method for this, but that's about how it should work.
From the comments, he's requiring you to inherit from a list and override its ToString() method, and then inherit from a list of that list and override its ToString() method.
First, the inner list (for lack of a better term):
public class InnerList : List<int>
{
public override string ToString()
{
// return the contents of the list somehow formatted as strings.
return string.Join(" ", this);
}
}
Next, a list of that list:
public class OuterList : List<InnerList>
{
public override string ToString()
{
var result = new StringBuilder();
ForEach(inner =>
{
if (inner != null) result.AppendLine(inner.ToString());
});
return result.ToString();
}
}
The ToString() method of the outer list works by calling the ToString() method of all of the lists it contains.
I'm obviously making up what goes in the overridden methods. But this is how you would override them according to the requirements you specified. In "real life" this wouldn't make any sense. We might declare a List<List<int>> without creating any new classes, and then write code to render it as a string. We could write code to render the same List<List<int>> two different ways. If we do this by overriding ToString() it suggests that we would create different inherited classes to format the numbers differently.
(Some courses tend to over-emphasize inheritance. It's useful, but they make it seem like it's the answer to everything.)
Note that there's also no need for either list to populate itself. That just makes it more confusing. You can write separate code to add numbers to it.

Two dimensional ReadOnlyObservableCollection

I want to bind Foo.Data property and I need it to be two dimensional ObservableCollection. Since I don't want Data property to be changed outside of the Foo class I'm trying to expose it as ReadOnlyObservableCollection. But updating the encapsulated _data field don't update the Data property.
public sealed class Foo
{
private readonly ObservableCollection<ObservableCollection<string>> _data;
public Foo()
{
_data = new ObservableCollection<ObservableCollection<string>>();
// this line gives compile time error
// cannot convert from ObservableCollection<ObservableCollection<string>> to ObservableCollection<ReadOnlyObservableCollection<string>>
// Data = new ReadOnlyObservableCollection<ReadOnlyObservableCollection<string>>(_data);
// Fill the _data variable
for (var i = 0; i<10; i++)
{
var t = new ObservableCollection<string>();
for (var j = 0; j<10; j++)
{
t.Add(i + "+" + j);
}
_data.Add(t);
}
var tmp = new ObservableCollection<ReadOnlyObservableCollection<string>>();
foreach (var row in _data)
{
tmp.Add(new ReadOnlyObservableCollection<string>(row));
}
Data = new ReadOnlyObservableCollection<ReadOnlyObservableCollection<string>>(tmp);
}
public ReadOnlyObservableCollection<ReadOnlyObservableCollection<string>> Data { get; }
public void RemoveItem(int x, int y)
{
_data[x].RemoveAt(y); // This does update the Data collection.
}
public void RemoveRow(int x)
{
_data.RemoveAt(x); // This does not update the Data collection.
}
}
Here is a working sample.
FYI: If you want to edit or rerun the code, just click on fork.
I've searched the web about it but I couldn't find anything. Is not two dimensional ObservableCollections a thing, is there a better practice?
The RemoveRow method does not update the Data collection because _data is not related to Data (except that they share some content). The collection related to Data is tmp, so I would try the following:
Make tmp class member and give it a name (e.g. _rowData)
rename _data to _itemData
use _rowData in RemoveRow
This is the result:
public sealed class Foo
{
private readonly ObservableCollection<ObservableCollection<string>> _itemData;
private readonly ObservableCollection<ReadOnlyObservableCollection<string>> _rowData;
public Foo()
{
_itemData = new ObservableCollection<ObservableCollection<string>>();
// Fill the _itemData variable
for (var i = 0; i<10; i++)
{
var t = new ObservableCollection<string>();
for (var j = 0; j<10; j++)
{
t.Add(i + "+" + j);
}
_itemData .Add(t);
}
_rowData = new ObservableCollection<ReadOnlyObservableCollection<string>>();
foreach (var row in _itemData )
{
_rowData.Add(new ReadOnlyObservableCollection<string>(row));
}
Data = new ReadOnlyObservableCollection<ReadOnlyObservableCollection<string>>(_rowData);
}
public ReadOnlyObservableCollection<ReadOnlyObservableCollection<string>> Data { get; }
public void RemoveItem(int x, int y)
{
_itemData[x].RemoveAt(y);
}
public void RemoveRow(int x)
{
_rowData.RemoveAt(x);
}
}

How can I add a specified number of list elements to an ILIST?

I have a class as follows:
public class ABC {
public IList<TextFillerDetail> TextFillerDetails
{ get { return _textfillerDetails; } }
private List<TextFiller> _textfillerDetails = new List<TextFiller>();
}
I instantiate this class and add some TextDetails to it:
var ans = new ABC();
ans.TextDetails.Add(new TextDetail());
ans.TextDetails.Add(new TextDetail());
ans.TextDetails.Add(new TextDetail());
ans.TextDetails.Add(new TextDetail());
Is there a way that I could do this in one step by adding some code to the class such as a different kind of constructor. For example by passing in a number 5 to request that five elements be added?
var ans = new ABC(5);
You could add it as a constructor argument:
public class ABC()
{
public ABC(int count)
{
for (int i = 0; i < count; i++)
{
TextDetails.Add(new TextDetail());
}
}
// Stuff
}
Sure, you could use a constructor that will initialize the list:
public class ABC
{
public ABC(int count)
{
if (count < 1)
{
throw new ArgumentException("count must be a positive number", "count");
}
_textfillerDetails = Enumerable
.Range(1, count)
.Select(x => new TextDetail())
.ToList();
}
public IList<TextFillerDetail> TextFillerDetails { get { return _textfillerDetails; } }
private List<TextFiller> _textfillerDetails;
}
Sure:
public class ABC {
public IList<TextFillerDetail> TextFillerDetails
{ get { return _textfillerDetails; } }
public ABC(int capacity)
{
_textfillerDetails = new List<TextFiller>(capacity);
}
private List<TextFiller> _textfillerDetails;
}
There are a few ways:
Use an initializer; it saves a little typing:
var ans = new ABC{
new TextDetail(),
new TextDetail(),
new TextDetail(),
new TextDetail(),
new TextDetail(),
}
Better idea: Use Linq to repeat an initialization lambda:
var ans = Enumerable.Repeat(0,5).Select(x=>new TextDetail()).ToList();
You could put in an overloaded constructor that takes the number of items to add as a parameter.
But why do you need to do that? Couldn't you just add TextDetail objects to your list as necessary?
Just for this task , Yes,
private List<TextFiller> _textfillerDetails = new List<TextFiller>();
public ABC(int capacity)
{
for(int index = 0; index < capacity; index ++)
_textfillerDetails.Add(new TextDetail());
}
You can use a for loop or linq:
public class ABC
{
public IList<TextFillerDetail> TextFillerDetails { get; private set }
public ABC() : this(0)
{
}
public ABC(int count)
{
TextFIllerDetails = Enumerable.Range(0,count)
.Select(x => new TextFillerDetail())
.ToList();
}
}
Consider using also,
IEnumerable or ICollection or IQueryable objects.
Ray Akkanson

Categories