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.
Related
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();
}
}
I'm new and struggling with object orientated programming. I want to use only the return value in my third method 'tableinfo' however i don't know how to transfer only this value to the other methods, without running the first two methods again. All i want to do is transfer only the value that the user enters over to the third method and not have to put in the values two times each, this is the only way i know to get the value across and i would really appreciate if anyone could help me to just get the return value. This code is a tiny snippet of what i'm trying to do and it's purpose is not important, i just wanted to create an example to try and allow people to understand what i mean.
Thank you in advance!
class Program
{
static void Main(string[] args)
{
TableOrder TO = new TableOrder();
TO.TableNumber();
TO.NumberOfPartons();
TO.tableinfo();
}
}
class TableOrder
{
int tablenumber;
string inputtablenumber;
int numberAtTable;
string inputNumberAtTable;
public int TableNumber()
{
Console.Write("please enter the table number:");
inputtablenumber = Console.ReadLine();
tablenumber = int.Parse(inputtablenumber);
return tablenumber;
}
public int NumberOfPartons()
{
Console.Write("please enter how many people are seated: ");
inputNumberAtTable = Console.ReadLine();
numberAtTable = int.Parse(inputNumberAtTable);
return numberAtTable;
}
public void tableinfo()
{
int tablenum = TableNumber();
Console.Write(tablenumber + 1);
int patrons = NumberOfPartons();
Console.WriteLine(numberAtTable + 1);
}
}
It looks like you might be confused on the difference between methods, properties, and fields. Your function TableNumber() might be more accurately called AskUserForTableNumber() or GetTableNumberFromInput(). Something like that. You are also both setting a member field and returning the value. So there are a bunch of ways you could store and retrieve that value. If the member field tablenumber was marked as public, you could access it. Or in your main function you could do this:
int tablenum=TO.TableNumber();
and then reuse that value.
Another odd thing you are doing is storing the input string as a member field. If you don't need to reference that string again, then there's no reason for that to be a member of the TableOrder object, it could be a local variable to the function that is doing the input.
But it seems like you are trying to use TableOrder.TableNumber like a property. And that very well may be the right thing to do, but not in the way that you are doing it. Here is a (sort of fancy) way of doing something similar, which also uses a concept of lazy-loading...
class TableOrder
{
private int? _tablenumber;
public int TableNumber
{
get
{
return _tablenumber ?? (_tablenumber=GetTableNumberFromInput());
}
set
{
_tablenumber = value;
}
}
private static int GetTableNumberFromInput()
{
Console.Write("please enter the table number:");
string inputtablenumber = Console.ReadLine();
return int.Parse(inputtablenumber);
}
//(and so on for other member properties)
}
This way, the first time you try to access table number, it will ask the user for the value. Afterward, you will already have the value, so it will not ask again. Note that this type of approach is not really necessary, and is mainly useful for waiting to load a value until you need to use that value. Instead you could just do something like: TableOrder.TableNumber = GetTableNumberFromInput();
First of all, you can remove the calls in your main since the method tableinfo() will call them:
class Program
{
static void Main(string[] args)
{
TableOrder TO = new TableOrder();
TO.tableinfo();
}
}
Second, you want to use the class variables that you already declared,
The returned value of the two functions are stored inside those and you can output them with Write.
public void tableinfo()
{
tablenumber = TableNumber();
Console.Write(tablenumber + 1);
numberAtTable = NumberOfPartons();
Console.WriteLine(numberAtTable + 1);
}
In the scope of this function, the return values (return numberAtTable and return tablenumber) don't exist anymore, they are stored in whats left of the called functions.
Suppose I have this code:
public sealed class MyStruct {
// ... snip
public uint[] ItemStatValue { get; set; }
// ... snip
}
// MainForm.cs
// ...
Generator.GenerateColumns(this.ContentListView, structure, true);
ContentListView.SetObjects(_records);
// ...
Is there a way to instruct GenerateColumns to treat each element of the ItemStateValue property as a column on its own, and appropriately name them ? ("Item Stat Value 1", "Item Stat Value 2", etc) Currently, it just calls ToString() on the object, thus returning System.Type.UInt32[]. Not exactly what I'd want.
I'm using http://www.codeproject.com/Articles/16009/A-Much-Easier-to-Use-ListView
Cheers!
No, that is not possible. The OLV uses reflection on the type of the specified item to gather the required information. If you supply an IEnumerable it just looks at the type of the first item.
The Generator has no clue and does not care about the actual instances of your items. Also, it wouldn't make much sense in your proposed case, since the number of elements could differ between each struct.
How many items are going to be in the array? ListViews have a fixed number of columns, i.e. each row has the same number of columns.
If you know there is going to be, say, 20 possible stats, just generate the columns.
const int numberOfColumns = 20;
for (int i = 0; i < numberOfColumns; i++) {
var statIndex = i;
var column = new OLVColumn();
column.Name = "Stat" + i;
column.AspectGetter = delegate(object x) {
MyStruct myStruct = (MyStruct)x;
return statIndex < myStruct.ItemStatValue.Length ? (uint?)myStruct.ItemStatValue[statIndex] : null;
};
column.AspectToStringConverter = delegate(object x) {
uint? value = (uint?)x;
return value.HasValue ? String.Format("Stat value: {0}", value.Value) : String.Empty;
};
this.ContentListView.AllColumns.Add(column);
}
this.ContentListView.RebuildColumns();
Call this after the GenerateColumns()
#Grammarian
So after looking around in the code, I noticed aspect getters for fields. However, Generator.GenerateColumns didn't seem to use its third boolean parameter, named allProperties.
So I threw together this quick code, and sure enough, it worked. It doesn't seem to cause any bug either, which is great.
Here is a gist:
https://gist.github.com/Warpten/c792ad66ad20cc69a918
Note: this also requires that you allow OLVColumnAttribute and OLVIgnoreAttribute to be applied to fields. That's easy enough ;)
Cheers!
So I have a dictionary whose index is an int, and whose value is a class that contains a list of doubles, the class is built like this:
public class MyClass
{
public List<double> MyList = new List<double>();
}
and the dictionary is built like this:
public static Dictionary<int, MyClass> MyDictionary = new Dictionary<int, MyClass>();
I populate the dictionary by reading a file in line by line, and adding the pieces of the file into a splitstring, of which there is a known number of parts (100), then adding the pieces of the string into the list, and finally into the dictionary. Here's what that looks like:
public void DictionaryFiller()
{
string LineFromFile;
string[] splitstring;
int LineNumber = 0;
StreamReader sr = sr.ReadLine();
while (!sr.EndOfStream)
{
LineFromFile = sr.ReadLine();
splitstring = LineFromFile.Split(',');
MyClass newClass = new MyClass();
for (int i = 1; i < 100; i++)
{
newClass.MyList.Add(Convert.ToDouble(splitstring[i]));
}
MyDictionary.Add(LineNumber, MyClass);
LineNumber++;
}
}
My question is this: is I were to then read another file and begin the DictionaryFiller method again, could I add terms to each item in the list for each value in the dictionary. What I mean by that is, say the file's 1st line started with 10,23,15,... Now, when I read in a second file, lets say its first line begins with 10,13,18,... what I'm looking to have happen is for the dictionary to have the first 3 doubles in its value-list (indexed at 0) to then become 20,36,33,...
Id like to be able to add terms for any number of files read in, and ultimately then take their average by going through the dictionary again (in a separate method) and dividing each term in the value-list by the number of files read in. Is this possible to do? Thanks for any advice you have, I'm a novice programmer and any help you have is appreciated.
Just Replace
newClass.MyList.Add(Convert.ToDouble(splitstring[i]))
with
newClass.MyList.Add(Convert.ToDouble(splitstring[i]) + MyDictionary[LineNumber].GetListOfDouble()[i])
and then replace
MyDictionary.add(Linenumber, Myclass)
with
MyDictionary[linenumber] = MyClass
Just makes sure that the MyDictionary[LineNumber] is not null before adding it :)
Something like this would work
If(MyDictionary[LineNumber] == null)
{
MyDictionnary.add(LIneNUmber, new List<double>());
}
If(MyDictionary[LineNUmber][i] == null)
{
return 0;
}
My solution does not care about list size and it done at reading time not afterward, which should be more efficient than traversing your Dictionary twice.
var current = MyDictionary[key];
for(int i = 0; i < current.MyList.Length; i++)
{
current.MyList[i] = current.MyList[i] + newData[i];
}
Given both lists have same length and type of data.
You can get the custom object by key of the dictionary and then use its list to do any operation. You need to keep track of how many files are read separately.
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.
}
}