How to create a collection of classes that can be iterated over? - c#

I have a series of properties for an object which are themselves a class:
private ClassThing Thing1;
private ClassThing Thing2;
private ClassThing Thing3;
private class ClassThing
{
public string Name;
public int Foos;
}
In some areas I need to be able to access each property specifically, for example:
label1.Text = Thing1.Name;
However, it is also desirable to create a foreach loop to access each one, like this:
string CombinedString;
foreach(ClassThing Thing in SomeCollection)
{
CombinedString += Thing.Name;
}
The end result must be XML serializable. These examples are very basic, but I hope they more easily demonstrate my need.
I tried creating a dictionary of these properties instead, but a dictionary is not XML serializable. I'd like to simply make all of these properties members of a class that itself can be iterated over, but I'm not sure how.
Can anyone point me in the right direction?

I hope this clarifies some things for you, since i am not entirely sure i understand your question.
//many normal classes can be made xml serializable by adding [Serializable] at the top of the class
[Serializable]
private class ClassThing
{
public string Name { get; set; }
public int Foos { get; set; }
}
//here we create the objects so you can access them later individually
ClassThing thing1 = new ClassThing { Name = "name1", Foos = 1 };
ClassThing thing2 = new ClassThing { Name = "name2", Foos = 2 };
ClassThing thing3 = new ClassThing { Name = "name3", Foos = 3 };
//this is an example of putting them in a list so you can iterate through them later.
List<ClassThing> listOfThings = new List<ClassThing>();
listOfThings.Add(thing1);
listOfThings.Add(thing2);
listOfThings.Add(thing3);
//iteration example
string combined = string.Empty;
foreach (ClassThing thing in listOfThings)
{
combined += thing.Name;
}
//you could also have created them directly in the list, if you didnt need to have a reference for them individually, like this:
listOfThings.Add(new ClassThing { Name = "name4", Foos = 4 });
//and more advanced concepts like linq can also help you aggregate your list to make the combined string. the foreach makes the code more readable though. this gives the same result as the foreach above, ignore it if it confuses you :)
string combined = listOfThings.Aggregate(string.Empty, (current, thing) => current + thing.Name);
//Here is an example of how you could serialize the list of ClassThing objects into a file:
using (FileStream fileStream = new FileStream("classthings.xml", FileMode.Create))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<ClassThing>));
xmlSerializer.Serialize(fileStream, listOfThings);
}
To be able to serialize the objects using this method, they cannot contain a constructor, which is why we use the new ClassThing{Name="",Foos=0} way of creating them.

You're looking for an implementation of the IEnumerable interface. See this link for a quick description of how to implement it.

class MyClass
{
private ClassThing Thing1;
private ClassThing Thing2;
private ClassThing Thing3;
internal IEnumerable<ClassThing> GetThings()
{
yield return Thing1;
yield return Thing2;
yield return Thing3;
}
void Test()
{
foreach(var thing in this.GetThings())
{
//use thing
}
}
}

public List<ClassThing> Things = new List<ClassThing>();
Then you can run your foreach over .Things

Related

What kind of data structure to use?

I am working on a project where I need to keep track of:
5-6 Root items of just a string name
Each root item need to have multiple children of different identifier types (int, string, float, etc). All the children of one root will be the same type but each root will have different children types
user will need to be able to add/delete children from each root
i will later need to access each children individually and perform string manipulations and parsing when needed
I've thought about maybe using a dictionary where the Key is a string and Values are lists of objects. Or having a unique class for each root item and each class will include a List of children.
Does anyone have any good suggestions? I'm still quite new to OOP, please bear with me :)
Thanks!
public interface IRoot {}
public class RootItem<T> : IRoot
{
public string Name { get; set; }
public List<T> Children {get; set; }
}
And then keep a Dictionary<string, IRoot> to hold them all.
Dictionary<string, IRoot> hair = new Dictionary<string, IRoot>();
hair.Add(
new RootItem<int>()
{
Name = "None",
Children = new List<int>() {1, 2, 3, 4}
}
);
hair.Add(
new RootItem<decimal>()
{
Name = "None",
Children = new List<decimal>() {1m, 2m, 3m, 4m}
}
);
How about a generic class with a List<T> to contain the children:
public class Root<T>
{
private List<T> children = null;
public Root(string name)
{
Name = name;
}
public string Name { get; set; }
public List<T> Children
{
get
{
if (children == null)
{
children = new List<T>();
}
return children;
}
}
}
Root<int> intRoot = new Root<int>("IntRoot");
intRoot.Children.Add(23);
intRoot.Children.Add(42);
Root<string> stringRoot = new Root<string>("StringRoot");
stringRoot.Children.Add("String1");
stringRoot.Children.Add("String2");
stringRoot.Children.Add("String3");
stringRoot.Children.Add("String4");
If you want to hold all the roots in one object, you could write your own class or use a Tuple:
var rootGroup = Tuple.Create(intRoot, stringRoot);
// intRoot is accessible as rootGroup.Item1
// stringRoot is accessible as rootGroup.Item2
Sounds like Dictionary<string, Tuple<type1, type 2, etc>> is a good candidate.
The key will be the string(root). The children to the root is a Tuple. We can add items to tuple. Thanks for pointing thisout.
Good starting point on Tuple
Here's one way to go about it. There's a lot of casting that needs to happen, but it gets the job done:
static void Main(string[] args)
{
Dictionary<string, IRootCollection> values = new Dictionary<string, IRootCollection>();
values["strings"] = new RootCollection<string>();
(values["strings"] as RootCollection<string>).Add("foo");
(values["strings"] as RootCollection<string>).Add("bar");
values["ints"] = new RootCollection<int>();
(values["ints"] as RootCollection<int>).Add(45);
(values["ints"] as RootCollection<int>).Add(86);
}
interface IRootCollection { }
class RootCollection<T> : List<T>, IRootCollection { }

How can I search for a specific struct value? Maybe a better approach?

I'm trying to find a struct I created earlier that has a specific value. Once I found it, I want to set variables on that struct. I don't know how to do this. Is there a better way of doing this? Maybe classes? Or should structs work?
For example, my struct:
public struct MyTest
{
public string device;
public string status;
public string revision;
public string number;
public string ledmo;
}
My Test Code:
MyTest thisTest=new MyTest();
thisTest.device=blah;
thisTest.number=blah2;
MyTest thisTest2=new MyTest();
thisTest2.device=blah5;
thisTest2.number=blah6;
//Another Part in my code.
//Need to find the MyTest Structure that 'device' variable = the string 'blah'
var Foundit=MyTest.find(device==blah);
Foundit.revision=blah9999;
I'd use a class, because Mutable structs are evil
Basically, because every struct is copied, even if you do find the right struct, you'll only ever change one copy. Lets say MyTest.find finds thisTest2 what happens is this
var Foundit = MyTest.Find(device==blah);
// The line above has made a copy of thisTest2, that copy is in FoundIt
Foundit.revision = "blah9999";
// You've changed revision in the copy of thisTest2,
// therefore the contents of thisTest2 remain unchanged
To do this with a class you'll need to keep every instance of the class you create in a list or other data structure, so you know you can look it up.
If you do this you also need to tell the list when you're finished with each object, otherwise they'll hang around forever and never get garbage collected.
Before I go any further, are you sure this is the best way to solve this problem?
Anyway, say your class is MyData, you can put a static factory method on this called Create, which will put each new MyData object into a list.
public class MyData
{
private static List<MyData> allMyDatas = new List<MyData>();
public static IEnumerable<MyData> AllInstances
{
get {return allMyDatas;}
}
public string Device {get; set;}
public string Status {get; set;}
public string Revision {get; set;}
public string Number {get; set;}
public string Ledmo {get; set;}
private MyData() // Private ctor ensures only a member
{ // function can create a new MyData
}
public static MyData Create()
{
var newData = new MyData();
allMyDatas.Add(newData);
return newData;
}
public static void Delete(MyData itemToRemove)
{
allMyDatas.Remove(itemToRemove);
}
}
Everywhere you use a MyData you'll need to Delete it when you're finished with it.
Your code becomes
var thisTest = MyData.Create();
thisTest.Device = "blah";
thisTest.Number = "blah2";
var thisTest2 = MyData.Create();
thisTest2.Device = "blah5";
thisTest2.Number = "blah6";
//Another Part in my code.
//Need to find the MyData Structure that 'device' variable = the string 'blah'
var Foundit = MyData.AllInstances.FirstOrDefault(md => md.Device == "blah");
if(Foundit != null)
Foundit.Revision = "blah9999";
Changing FoundIt now also changes thisTest
P.S.: It's important that nothing outside MyData can new an instance of MyData. If it could, then there would be an instance of MyData that you couldn't find in AllInstances. Declaring the constructor private means a compiler error will be generated if code outside MyData tries something like var someData = new MyData
To be able to find instances of an object created earlier, these instances need to be saved somewhere.
One solution would be to put them into a list and later search that list:
var list = new List<MyTest>();
MyTest thisTest=new MyTest();
thisTest.device=blah;
thisTest.number=blah2;
list.Add(thisTest);
MyTest thisTest2=new MyTest();
thisTest2.device=blah5;
thisTest2.number=blah6;
list.Add(thisTest2);
Now you can search using LINQ:
var foundItems = list.Where(x => x.device == "blah");
foreach(var foundItem in foundItems)
{
foundItem.revision = "blah9999";
}
Please note:
This only works when you use classes instead of structs as Binary Worrier points out in his comment.
In this case a class would work better because of the dynamic string size and the fact that there are so many strings.
With your test code, you should be storing a List<MyTest> somewhere in that class and adding thisTest and thisTest2 to the list. You can later retrieve specific values (or all the values of a certain device) with the FindAll or similar methods.
List<MyTest> list = new List<MyTest>();
//add MyTests here...
var foundIt = list.FindAll(x => x.device == "blah");
You can use lists and Linq for that.
var test = new List<MyTest>();
//Add some items
var foundIt = test.SingleOrDefault(test => test.device == "abc");//Maximum one
if(foundIt != null)//Use a class for MyTest.
foundIt.device = "123"

Returning data from one method to another within a class

Thanks for help with the question I just submitted about anonymous classes. Now I understand more. Here's a bit more of an example:
public class abc {
public xx doAction() {
return ( new { ID = 5, Name= "Dave" } );
}
public void doStart() {
var a = doAction();
var b = a.ID;
var c = a.Name;
}
}
So am I correct in saying that the most ideal way to do this would be to declare a class XYX and use it like this:
public class abc {
public XYZ doAction() {
return ( new XYZ { ID = 5, Name= "Dave" } );
}
public void doStart() {
var a = doAction();
var b = a.ID;
var c = a.Name;
}
}
The class would be only used for this one data transfer between the two methods.
I think you meant: return new XYZ(5, "Dave")
Anyways, your solution is okay but there is no reason to create a new class simply to share data. You can use a hashtable/array/dictionary or whatever class suits you best to share data. If you want to do something special with the XYZ class, or it has methods you wish to call from it, then you would have to create a new class XYZ and return it. Though, if you just want to share data, use a data structure that's already available to your use.
That would work yes. If it is the most ideal or not is hard to say. Since you are using the variables "ID" and "Name" it kinda indicates that you are working with domain objects from a database, and if so, you will probably need the class for a lot more than just this one method.
What about the class ABC? What kind of class is that? Because you could also do this:
public class abc{
private int _id;
private string _name;
public void DoAction(){
_id = 5;
_name = "Dave";
}
public void DoStart(){
var b = _id;
var c = _name;
}
}
But remember to use proper naming for your classes, so you have an idea of what they are used for.
Yes, though if your class has trivial properties you can consider using existing .Net classes:
1) You can consider using System.Tuple (.Net 4.0) but you will not have good property names anymore:
var result = Tuple.Create(5, "Dave");
int id = result.Item1;
string name = result.Item2;
2) You can use KeyValuePair if it is applicable:
var result = new KeyValuePair<int, string>(5, "Dave");
int id = result.Key;
string name= result.Value;

Unable to update the contents of a Generic List

I have a simple class which has boolean field:
public struct Foo { bool isAvailable; }
Now I have a List of foos:
List < Foo > list = new List< Foo >();
Later on I enumerate each foo in the list and try to update its isAvailable field:
foreach(Foo foo in list) {
foo.isAvailable = true;
}
But the above code never updates the list. What am I doing wrong here and what's its remedy.
It's because Foo is a mutable struct.
When you fetch the value from the list, it's making a copy - because that's how value types behave. You're changing the copy, leaving the original value unchanged.
Suggestions:
You probably should be using a class
Don't create mutable structs. They behave in ways which can be hard to predict, or at least not the way you might expect when you're not explicitly thinking about it.
While you could change your code to iterate over the list in a different way and replace the value each time, it's generally a bad idea to do so. Just use a class... or project your list to a new list with the appropriate values.
Original answer, when Foo was a class
It should work fine. For example, here's a short but complete program which does work:
using System.Collections.Generic;
public class Foo
{
public bool IsAvailable { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name + ": " + IsAvailable;
}
}
class Test
{
static void Main()
{
List<Foo> list = new List<Foo>()
{
new Foo { Name = "First", IsAvailable = true },
new Foo { Name = "Second", IsAvailable = false },
new Foo { Name = "Third", IsAvailable = false },
};
Console.WriteLine("Before:");
list.ForEach(Console.WriteLine);
Console.WriteLine();
foreach (Foo foo in list)
{
foo.IsAvailable = true;
}
Console.WriteLine("After:");
list.ForEach(Console.WriteLine);
}
}
Try to adapt your current code to a similar short but complete program which doesn't work, post that, and we can work out what's going on.
You're using a struct as Foo, not a class. Structs are copied, not referenced, and therefore you only modify the copy and not the object stored in the list.
So you basically have two options:
Make it a class
Re-assign the result to the list. To do so, I'd iterate using an index instead of using foreach.
When you fill list, you need to create new istance for each Foo Class.
List list = new List();
Foo foo = new Foo();
foo.isAvailable = false;
list.Add(foo);
foo = new Foo();
list.Add(foo);
foo = new Foo();
list.Add(foo);
if you fill on this way:
List list = new List();
Foo foo = new Foo();
list.Add(foo);
list.Add(foo);
list.Add(foo);
you are reference on same memory location on stack for each object.

Why adding custom objects to List<T> in ApplicationSettingsBase via constructor doesn't work?

This is pretty closely related to another SO question.
Using the example below, could someone explain to me why adding a new List<Foo> where each of Foo's properties are explicitly set causes the ApplicationSettingsBase.Save() method to correctly store the data, whereas adding a new Foo to the list via a constructor (where the constructor sets the property values) does not work? Thanks!
public class Foo
{
public Foo(string blah, string doh)
{
this.Blah = blah;
this.Doh = doh;
}
public Foo() { }
public string Blah { get; set; }
public string Doh { get; set; }
}
public sealed class MySettings : ApplicationSettingsBase
{
[UserScopedSetting]
public List<Foo> MyFoos
{
get { return (List<Foo>)this["MyFoos"]; }
set { this["MyFoos"] = value; }
}
}
// Here's the question...
private void button1_Click(object sender, EventArgs e)
{
MySettings mySettings = new MySettings();
// Adding new Foo's to the list using this block of code doesn't work.
List<Foo> theList = new List<Foo>()
{
new Foo("doesn't","work")
};
// But using this block of code DOES work.
List<Foo> theList = new List<Foo>()
{
new Foo() {Blah = "DOES", Doh = "work"}
};
// NOTE: I never ran both the above code blocks simultaneously. I commented
// one or the other out each time I ran the code so that `theList` was
// only created once.
mySettings.MyFoos = theList;
mySettings.Save();
}
This might be due to how you constructed your example. But using the given code, the "doesn't work" list is getting removed when you do the "does work" section. If you want both elements to be in theList at the end of the method, you can only have one new List<Foo>() call.
I stumbled upon the answer while trying to clarify my question just now. If I supply a default constructor to the Foo class:
public Foo() { }
--leaving everything else the same--then the values of the class are correctly stored in the user.config file when ApplicationSettingsBase.Save() is executed. Weird.

Categories