my problem is as follows:
Im building a console application which asks the user for the numbers of objects it should create and 4 variables that have to be assigned for every object.
The new objects name should contain a counting number starting from 1.
How would you solve this?
Im thinking about a class but im unsure about how to create the objects in runtime from userinput. Is a loop the best way to go?
What kind of class, struct, list, array .... would you recommend. The variables in the object are always the same type but i need to name them properly so I can effectivly write methods to perform operations on them in a later phase of the program.
Im just learning the language and I would be very thankful for a advice on how to approach my problem.
If I understand your problem correctly:
class MyClass
{
public int ObjectNumber { get; set; }
public string SomeVariable { get; set; }
public string AnotherVariable { get; set; }
}
// You should use keyboard input value for this
int objectsToCreate = 10;
// Create an array to hold all your objects
MyClass[] myObjects = new MyClass[objectsToCreate];
for (int i = 0; i < objectsToCreate; i++)
{
// Instantiate a new object, set it's number and
// some other properties
myObjects[i] = new MyClass()
{
ObjectNumber = i + 1,
SomeVariable = "SomeValue",
AnotherVariable = "AnotherValue"
};
}
This doesn't quite do what you described. Add in keyboard input and stuff :) Most of this code needs to be in some kind of Main method to actually run, etc.
In this case, I've chosen a class to hold your 4 variables. I have only implemented 3 though, and I've implemented them as properties, rather than fields. I'm not sure this is necessary for your assignment, but it is generally a good habit to not have publically accessible fields, and I don't want to be the one to teach you bad habits. See auto-implemented properties.
You mentioned a struct, which would be an option as well, depending on what you want to store in it. Generally though, a class would be a safer bet.
A loop would indeed be the way to go to initialize your objects. In this case, a for loop is most practical. It starts counting at 0, because we're putting the objects in an array, and array indexes in C# always start at 0. This means you have to use i + 1 to assign to the object number, or the objects would be numbered 0 - 9, just like their indexes in the array.
I'm initializing the objects using object initializer syntax, which is new in C# 3.0.
The old fashioned way would be to assign them one by one:
myObjects[i] = new MyClass();
myObjects[i].ObjectNumber = i + 1;
myObjects[i].SomeVariable = "SomeValue";
Alternatively, you could define a constructor for MyClass that takes 3 parameters.
One last thing: some people here posted answers which use a generic List (List<MyClass>) instead of an array. This will work fine, but in my example I chose to use the most basic form you could use. A List does not have a fixed size, unlike an array (notice how I initialized the array). Lists are great if you want to add more items later, or if you have no idea beforehand how many items you will need to store. However, in this case, we have the keyboard input, so we know exactly how many items we'll have. Thus: array. It will implicitly tell whoever is reading your code, that you do not intend to add more items later.
I hope this answered some questions, and raised some new ones. See just how deep the rabbit hole goes :P
Use a list or an array. List example:
int numberOfObjects = 3;
List<YourType> listOfObjects = new List<YourType>();
for(int i = 0 ; i < numberOfObjects ; i++ )
{
// Get input and create object ....
// Then add to your list
listOfObjects.Add(element);
}
Here, listOfObjects is a Generic list that can contain a variable number of objects of the type YourType. The list will automatically resize so it can hold the number of objects you add to it. Hope this helps.
If I understood what you are asking you could probably do something like this:
class Foo
{
private static int count;
public string name;
public Foo(...){
name = ++count + "";
}
}
I'm guessing what you're trying to do here, but this is a stab in the dark. The problem I'm having is dealing with the whole "the new objects name should contain a counting number starting from 1" thing. Anyway, here's my attempt:
public class UserInstantiatedClass
{
public int UserSetField1;
public int UserSetField2;
public int UserSetField3;
public int UserSetField4;
public string UserSpecifiedClassName;
}
public static class MyProgram
{
public static void Main(string [] args)
{
// gather user input, place into variables named
// numInstances, className, field1, field2, field3, field4
List<UserInstantiatedClass> instances = new List< UserInstantiatedClass>();
UserInstantiatedClass current = null;
for(int i=1; i<=numInstances; i++)
{
current = new UserInstantiatedClass();
current.UserSpecifiedClassName = className + i.ToString(); // adds the number 1, 2, 3, etc. to the class name specified
current.UserSetField1 = field1;
current.UserSetField2 = field2;
current.UserSetField3 = field3;
current.UserSetField4 = field4;
instances.Add(current);
}
// after this loop, the instances list contains the number of instances of the class UserInstantiatedClass specified by the numInstances variable.
}
}
Related
I'm working on a school project in Windows Forms where we're making an animal registry. I have an Animal class where the animal object is created with the properties Id, Name, Age, Gender, and Friendly. I also have an AnimalManager class that handles a list and through which more animals can be added. At runtime, when having filled out the appropriate boxes with information and pressed the Add Animal-button, the information should be added to a row in a listview (the important part of the task. Everything was peaceful when I could just display it in a listbox).
When I printed my information to a listbox I simply sent a string with the appropriate information through public string AnimalInformation() from the Animal class to the AnimalManager that compiled an array of it and sent it to Form1 to be printed. Since I want to display it in a listview, I figured I should make AnimalInformation() into an array instead, so that I get a 2D array after passing through the AnimalManager, much like it will be displayed when printed. However, I get the exception message System.NullReferenceException: 'Object reference not set to an instance of an object.' in my AnimalManager when running the program and trying to add the animal.
This is the method in the Animal class:
public string[] AnimalInformation()
{
string[] strOut = { id, name, age.ToString(), gender.ToString(), FriendlyStr()};
return strOut;
}
This is the method in the AnimalManager class:
public string[][] GetAnimalInfoArray()
{
string[][] animals = new string[animalList.Count][];
for(int i = 0; i < animalList.Count; i++)
{
Animal animal = animalList[i];
for(int j = 0; j < animal.CountAnimalInfo(); j++)
{
string[] info = animal.AnimalInformation();
animals[i][j] = info[j];
}//here comes the exception
}
return animals;
}
And since I am not too familiar with listview (read: not at all), here's the loop I wrote for printing it all into the listview in my UpdateGUI() method, in case this is what is causing the trouble:
if (manager.Count() > 0)
{
foreach(string[] row in manager.GetAnimalInfoArray())
{
foreach(string item in row)
lvwAnimals.Items.Add(item);
}
}
I've been at this for hours and don't know what's up or down anymore. Am I even on the right track? Do I have to rework this completely? What am I doing wrong to get an error message after that curly bracket?
The first problem is that you're creating an array of arrays but not allocating the arrays in the array... which is mildly confusing, but this is the line:
string[][] animals = new string[animalList.Count][];
animals is an array of string[]. At this point, each element in the animals array is null, not an array. The point where you're having a problem is this:
animals[i][j] = info[j];
At this point animals[i] is uninitialized (null), so there is no array for you to index with j.
There are a number of solutions to the problem, but the most direct method is to simply assign the result of calling AnimalInformation to the array slot and be done with it:
public string[][] GetAnimalInfoArray()
{
string[][] animals = new string[animalList.Count][];
for(int i = 0; i < animalList.Count; i++)
animals[i] = animalList[i].AnimalInformation();
return animals;
}
If you're OK with using LINQ there's an even simpler option: ToArray().
public string[][] GetAnimalInfoArray()
=> animalList.Select(a => a.AnimalInformation()).ToArray();
A couple of notes on the rest of the code...
Your inner loop calls CountAnimalInfo() and AnimalInformation() for each item in the information array. That's 5 times you're calling those two methods, creating at least one array each time you do (and I'm assuming you're not calling AnimalInformation() from inside CountAnimalInfo(), if you are then that's two arrays per item). It would be better to simply call it once and use the resultant array for the loop, if you have to loop at all.
for (int i = 0; i < animalList.Count; i++)
{
var info = animalList[i].AnimalInformation();
animals[i] = new string[info.Length];
for (int j = 0; j < info.Length; j++)
animals[i][j] = info[j];
}
You're spreading what appears to be display code across several methods and classes. While there are times when it's useful to be able to override things in sub-classes, it's generally preferable (in my experience at least) to have the display code in one place: a single method or tightly coupled group of methods in a single class. An Animal doesn't need to know how it is being displayed, it just needs to present properties that other code can use. Your AnimalManager class probably doesn't need to act as go-between for your display code either, it's up to the display code to figure out how things should look. Try this:
foreach (var animal in manager.animalList)
{
lvwAnimals.Items.Add(animal.id);
lvwAnimals.Items.Add(animal.name);
lvwAnimals.Items.Add(animal.age.ToString());
lvwAnimals.Items.Add(animal.gender.ToString());
lvwAnimals.Items.Add(animal.FriendlyStr());
}
This way you've separated the 'display' concern out from the non-display classes, letting them focus more on doing their own job. And extra bonus, it's a lot less lines of code to debug later.
I know this doesnt directly answer , JeremyLakeMan comments about why you have a problem at the moment. But here is what I would do
Given an IEnumerable of Animals called animalList (which you already have)
Assuming Animal Looks Like this
public class Animal{
public string ID;
public String Name;
public int Age;
}
Now
foreach(var animal in animals)
{
lvwAnimals.Items.Add(animal.ID);
lvwAnimals.Items.Add(animal.Name);
lvwAnimals.Items.Add(animal.Age.ToString());
}
thats it, the whole GetAnimalInfoArray is not needed
I have a c# class that looks like this:
public class MemberData
{
public int meme_ck;
public string meme_name;
public bool meme_active;
public MemberData(int ck2, string name2, bool active2)
{
meme_ck = ck2;
meme_name = name2;
meme_active = active2;
}
}
I have made two arrays out of that class:
private MemberData[] memarray1 = new MemberData[10000];
private MemberData[] memarray2 = new Memberdata[10000];
Over the course of my application I do a bunch of stuff with these two arrays and values change, etc. Member's name or active status may change which results in the ararys becoming different.
Eventually I need to compare them in order to do things to the other one based on what results are kicked out in the first one.
For example, member is de-activated in the first array based on something application does, I need to update array 2 to de-activate that same member.
I am trying to use some database design philosphy with the int CK (contrived-key) to be able to rapidly look up the entry in the other array based on the CK.
Since I can't figure it out I've had to resort to using nested for loops like this, which sucks:
foreach (Memberdata md in memarray1)
{
foreach (Memberdatamd2 in memarray2)
{
if (md.ck = md2.ck)
{
//de-activate member
}
}
}
Is there a better way to do this? I just want to find the index in the second array based on CK when I have the CK value from the first array.
Any other tips or advice you have about structure would be appreciated as well. Should I be using something other than arrays? How would I accomplish this same thing with Lists?
Thanks!
Should I be using something other than arrays?
Yes. Don't use arrays; they are seldom the right data structure to use.
How would I accomplish this same thing with Lists?
Lists are only marginally better. They don't support an efficient lookup-by-key operation which is what you need.
It sounds like what you want is instead of two arrays, two Dictionary<int, MemberData> where the key is the ck.
I totally agree with Eric Lippert's answer above. It is better you do not use Array.
Same thing can be achieved using List<MemberData>. You can use LINQ as well to query your DataStructure.
Following is one of the way just to achieve your result using array
class Program
{
static MemberData[] memarray1 = new MemberData[10000];
static MemberData[] memarray2 = new MemberData[10000];
static void Main(string[] args)
{
for (int i = 0; i < memarray1.Length; i++)
{
memarray1[i] = new MemberData(i + 1, "MemName" + i + 1, true);
memarray2[i] = new MemberData(i + 1, "MemName" + i + 1, true);
}
// SIMULATING YOUR APP OPERATION OF CHANGING A RANDOM ARRAY VALUE IN memarray1
int tempIndex = new Random().Next(0, 9999);
memarray1[tempIndex].meme_name = "ChangedName";
memarray1[tempIndex].meme_active = false;
//FOR YOUR UDERSTADNING TAKING meme_ck IN AN INTEGER VARIABLE
int ck_in_mem1 = memarray1[tempIndex].meme_ck;
//FINDING ITEM IN ARRAY2
MemberData tempData = memarray2.Where(val => val.meme_ck == ck_in_mem1).FirstOrDefault();
// THIS IS YOUR ITEM.
Console.ReadLine();
}
}
My question is sort of like the one found here:
How do I name variables dynamically in C#?
However its a bit different so I'm wondering if its possible.
I'm trying to read in a bunch of strings from a .settings file.
I have them all named Time1, Time2,Time3 etc...
I want the User to be able to add more Times to the file so there could be Time100 or more.
I have a Size in the settings file that will keep track of the amount of Time Variables.
I want to write something that will read in all of the Time strings. I think it would be silly to pre-fill the .settings file with 100 Time Variables so I know they are there and then manually read in each one.
So I'm wondering if there is a way where I can read in Timei or Time+i where I is an integer that I can put in a loop that will find them all.
(note that the data is string not time, its just going to be converted to days of the week)
Such as: (Days is from ApplicationSettingsBase [aka file add new Settings1.settings]
public static int AvDaysIndex = Days.Default.Size; //This holds the number of items in Days
public static DayOfWeek[] AvailableDays = new DayOfWeek[AvDaysIndex]; //This is where I wants to read in all the variables Aka Time1 Time2 Times3
public ReadInDays() //Reads in from the .settings File
{
if(AvDaysIndex>0) // Makes sure there is something in Days to read
{
int I=0;
//I can Manually do the following
AvailableDays[I++] = Days.Default.Time1;
AvailableDays[I++] = Days.Default.Time2;
AvailableDays[I++] = Days.Default.Time3; //etc...
//Is there a way to do something like this
for (int i = 0; i < AvDaysIndex; i++) //reads in each time
{
AvailableDays[i] = Days.Default.Time +i;//where I would be added to the variable name to find it?
//Or something like
AvailableDays[i] = Days.Default.Time(I.tostring())
}
}
}
Hopefully all that at least makes it clear what I'm trying to do.
Edit - I'm starting to think my issue is actually with the .settings file. and that if I just read values in from another file type where the values don't have names I can easily read them in even though there is a variable number of elements in the file.
Solution -
for (int i = 0; i < Index; i++)
{
AvailableDays[i] = getFromFile(_Days.Default.Properties["Time" + (i+1).ToString()].DefaultValue.ToString());
AvailableTimes[i] = Convert.ToDateTime(_Times.Default.Properties["Time" + (i + 1).ToString()].DefaultValue);
}
It was all in figuring out how to read in from the .settings file and instead of reading it in directly aka Days.Default.Time1; I had to to do a generic lookup from Days.Default.Properties and then I could create a dynamic name and find it. You guys probably were trying to tell me how to do this, I just didn't understand.
Thanks again to all those that helped.
I would use a hashtable/dictionary to store the Days.Default.TimeX variations
hashtable["Time1"]...hashtable["TimeN"]
As already mentioned a hashtable or a dictionary would probably serve you best. If you go the dictionary route you can create a string/int indexer on the class and you would be able to alter your code slightly:
http://msdn.microsoft.com/en-us/library/2549tw02%28v=vs.80%29.aspx - Example of creating indexer on a class:
Example Indexer Class:
public class Default
{
private Dictionary<int, DayOfWeek> _values = new Dictionary<int,DayOfWeek>();
public DayOfWeek this[int index]
{
get
{
if (_values.ContainsKey(index))
return _values[index];
else
return null;
}
set
{
_values[index] = value;
}
}
}
Original:
AvailableDays[i] = Days.Default.Time(I.tostring())
Would become:
AvailableDays[i] = Days.Default.Time[I];
Reflection is always an option too and i have an example below that is in a Windows Console Application:
public class Default
{
public int Time1 { get; set; }
public int Time2 { get; set; }
public int Time3 { get; set; }
}
class Program
{
static void Main(string[] args)
{
Default d = new Default();
Type t = d.GetType();
foreach (var info in t.GetProperties())
{
//SET VALUE
info.SetValue(d, 1);
}
foreach (var info in t.GetProperties())
{
//GET VALUE
Console.WriteLine("Property: {0}", info.Name);
Console.WriteLine("Value: {0}", info.GetValue(d));
}
//OR JUST ONE PROPERTY
Console.WriteLine("Time1 Property Value: {0}", t.GetProperty("Time1").GetValue(d));
Console.ReadLine();//PAUSE THE CONSOLE AFTER PROCESSING
}
}
In your example using reflection:
Days.Default.GetType().GetProperty("Time" + I.ToString()).GetValue(Days.Default) as DayOfWeek;
Another option could be to use Reflection. And getting the values from the enum on the fly.
See the link: How to Get Enum Values with Reflection in C#
However, using a Dictionary<string, DayOfWeek> will give you better performance and more readable code.
I think you could better resolve your problem by implementing your configuration using a
ConfigurationElementCollection. Then the 'names' of the configuration elements are irrelevant. You enumerate a collection of values and use those directly.
See here for an example; How to implement a ConfigurationSection with a ConfigurationElementCollection.
Today I've gone through what indexers are, but I am bit confused. Is there really a need for indexers? What are the advantages of using an indexer..... thanks in advance
I guess the simplest answer is to look at how you'd use (say) List<T> otherwise. Would you rather write:
string foo = list[10];
or
string foo = list.Get(10);
Likewise for dictionaries, would you rather use:
map["foo"] = "bar";
or
map.Put("foo", "bar");
?
Just like properties, there's no real need for them compared with just named methods following a convention... but they make code easier to understand, in my view - and that's one of the most important things a feature can do.
Indexers let you get a reference to an object in a collection without having to traverse the whole collections.
Say you have several thousands of objects, and you need the one before last. Instead of iterating over all of the items in the collection, you simply use the index of the object you want.
Indexers do no have to be integers, so you can use a string, for example, (though you can use any object, so long as the collection supports it) as an indexer - this lets you "name" objects in a collection for later retrieval, also quite useful.
I think zedo got closest to the real reason IMHO that they have added this feature. It's for convenience in the same way that we have properties.
The code is easer to type and easier to read, with a simple abstraction to help you understand.
For instance:
string[] array;
string value = array[0];
List<string> list;
string value = list[0]; //Abstracts the list lookup to a call similar to array.
Dictionary<string, int> map;
int value = map["KeyName"]; //Overloaded with string lookup.
Indexers allow you to reference your class in the same way as an array which is useful when creating a collection class, but giving a class array-like behavior can be useful in other situations as well, such as when dealing with a large file or abstracting a set of finite resources.
yes , they are very use of
you can use indexers to get the indexed object.
Taken from MSDN
Indexers are most frequently implemented in types whose primary purpose is to encapsulate an internal collection or array.
Full Story
for some reason, use indexer can let you create meaningful index to store or map your data. then you can get it from other side by the meaningful index.
using System;
/* Here is a simple program. I think this will help you to understand */
namespace Indexers
{
class Demo
{
int[] a = new int[10];
public int Lengths
{
get
{
return a.Length;
}
}
public int this[int index]
{
get
{
return a[index];
}
set
{
a[index] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Demo d = new Demo(); // Notice here, this is a simple object
//but you can use this like an array
for (int i = 0; i < d.Lengths; i++)
{
d[i] = i;
}
for (int i = 0; i < d.Lengths; i++)
{
Console.WriteLine(d[i]);
}
Console.ReadKey();
}
}
}
/*Output:
0
1
2
3
4
5
6
7
8
9
*/
I've been messing around with this for ages and I'm not getting any closer.
My current version is as below. The comments are what I think I'm doing.
The semantic is basically an index number (like a house number) and a list of attributes in an array. Then create an array 'street'. I want to be able to update the values of all elements in the current scope. The class is defined as high as possible so as to make the scope global. My ossified 'C' brain doesn't really understand things like lists and IEnumerable so I haven't tried to go that route. The code parser in the editor makes a bit of a mess of this - sorry.
public class house
{
// Ok, looking at this from the world of 'C' and thinking 'struct' like,
// I put my variables here.
public int my_id;
public long [] pl_id;
public house()
{
// I try to initialise the starting values, so I can carry out some tests later.
my_id = 0;
pl_id = new long[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
}
}
// I attempt to inform the compiler that I will be wanting an array of the house objects
// and call that array 'new_house'. Again, the code editor isn't keen.
house [] new_house;
private void button1_Click(object sender, EventArgs e)
{
// In the programs main routine (not *main*!), I then try to get the
// array 'new_house' populated with initialised 'house' objects
for (int idx = 0; idx < 10; idx++)
{
new_house[idx] = new house();
}
// And at some point in the future I wish to set or update the values arbitrarily. eg:
new_house[7].my_id = 123;
new_house[7].pl_id = 345678;
// any combination of attributes and id numbers is possible, so I use zero simply to see if they have been set, with -1 indicating failure / an absence of data-
}
}
Right. As I say, I've tried a lot of different ways to do this, and the main problem I am getting is that I never seem to correctly initialise the array 'new_house' and get null exceptions thrown when I try to assign anything. I can't believe something that seems so intuitively simple can be so hard to code, so where have I got it wrong (and I fully accept that there could be more than one conceptual or coding error in the above).
Comments on appropriateness of approach, and help with coding alike, gratefully accepted.
You need to instantiate the array before initializing items of it:
house[] new_house = new house[10];
Replace 10 with desired number of items.
In case you don't know the number, use List:
List<house> new_house = new List<house>()
Then you can dynamically add items using new_house.Add(item) and access them in foreach loop or through index new_house[i]
The first obvious problem with your code is that your constructor doesn't have the same name as the class. It should be this:
public house()
{
// ...
}
A second point is you don't need the constructor at all here:
public int my_id = 0; // The "= 0" is actually not needed here either.
public long[] pl_id = new long[10];
I would also suggest that you don't use arrays for things like houses on a street because house numbers won't necessarily be sequential. You can have gaps and even multiple houses with the "numbers" 5A and 5B. A dictionary might be a better choice.
IDictionary<string, house> houses = new Dictionary<string, house>();
If you really want to have sequential numbering you might want to consider a List<house> instead of an array so that it can be easily extended if new houses are built.
Finally I'd advise using PascalCase for classes. It will make your code much easier to read if you use the same standards as the rest of the .NET framework.
Change public game()
to public house()
Your constructor has to have the same name as the class.
A couple things:
new_house is never initialized. You can't use it until you've initialized it.
pl_id is an array, but you attempt to store a long in it (345678) -- you could change it to new int[] { 345678}.
You've got a method, game(), in the class house which looks and acts like a constructor. You would have to name it house() if it is meant to be a constructor.
not public game()
right: public house()
Always the constructor has to have the same name as the class.
Use List<T> for those collections. Try not to say you don't understand something because you are 'c' addicted. Try to say yourself you want to try something new and search for a good solution
namespace Myprog
{
// I attempt to inform the compiler that I will be wanting an array of the house objects
// and call that array 'new_house'
List<house> houselist = new List<house>();
private void button1_Click(object sender, EventArgs e)
{
// In the programs main routine (not *main*!), I then try to get the
// array 'new_house' populated with initialised 'house' objects
for (int idx = 0; idx < 10; idx++)
{
houselist.add(new house());
}
// And at some point in the future I wish to set or update the values arbitrarily. eg:
houselist[7].my_id = 123;
// any combination of attributes and id numbers is possible, so I use zero simply to see if they have been set, with -1 indicating failure / an absence of data-
}
}
}