C# - Set array size - c#

I'm trying to create a new class which contains an array but the size of it shouldn't be constant.
Let's say I have the Program.cs and I have a different class called Category.cs.
Category.cs looks like this:
class Category
{
static int MemberCount = 2;
private string[] ids = new string[MemberCount];
public string[] Ids
{
get { return ids; }
set { ids = value; }
}
...
My goal is to somehow modify MemberCount when I create a new object from this Class...
I hope it make sense...
Thank you! :-)

Assuming you actually want/need to use an array with the length fixed at object construction time (as opposed to say the List<T> wisely suggested in comments), you can add a constructor:
class Category
{
private readonly string[] ids;
public string[] Ids
{
get { return ids; }
}
public Category(int memberCount) {
ids = new string[memberCount];
}
}
Note that I have removed the setter on the Ids property as otherwise the array can be overwritten with one of an arbitrary length. Likewise I have made ids readonly.

Use a generic list or other collection class.
class Category
{
public List<string> Ids { get; set; }
Category()
{
Ids = new List<string>();
}
}

You can resize your array using this method:
Array.Resize(ref ids, newSizeOfArray);

Related

what is an optimal way to approach this list to array problem

class ProjectGroup
{
private List<string> members = new List<string>();
public List<string> Members { get { return members; } }
}
class Course
{
public bool AddStudent(string name)
{
ProjectGroup projectGroup = new ProjectGroup();
projectGroup.Members.Add(name);
return true;
}
}
So in this code I created a private list of members and accessed it with a public list Members which makes no sense for being a private in the first place. So instead I made a clone of the private list ToArray().
class ProjectGroup
{
private List<string> members = new List<string>();
public string[] Members { get { return members.ToArray(); } }
}
but that means I can't use projectGroup.Members.Add(name); anymore since Members is an array now.
How can I add string name to projectGroup.Members now?
The first code makes perfect sense. It's a read-only property so you can get the List object in order to add items or whatever but you cannot set the property, so you cannot replace the existing List with a completely different one. The thing is, you don't need the field at all. Just use the property:
public List<string> Members { get; } = new List<string>();
There will be a field created implicitly by the compiler but you don't need to use it so you don't need to declare it explicitly.
but that means I can't use projectGroup.Members.Add(name); anymore since Members is an array now.
How can I add string name to projectGroup.Members now?
It depends, you should ask yourself, will this ProjectGroup.Members changed over time or only populated once at creation time? Is the encapsulation actually worth the trouble?
Populated Once
If it populated once, you can use constructor. This way you can ensure the members is read-only.
class ProjectGroup
{
private List<string> members;
public string[] Members { get { return members.ToArray(); } }
public ProjectGroup(List<string> projectMembers)
{
//Ensure projectMembers cant be null
if(projectMembers == null)
throw new ArgumentNullException("projectMembers");
members = projectMembers;
}
}
You can then create an instance of the ProjectGroup this way:
var pg = new ProjectGroup(new List<string>(){"robert", "bob"});
Restricting Operations
If you want to limit the number of action you can do on the List<string>, you can add methods to expose the functionality you required. For example, let's say we want to validate name before being added into the members. You can add a method in ProjectGroup to do so (lets call it AddName).
class ProjectGroup
{
private List<string> members = new List<string>();
public string[] Members { get { return members.ToArray(); } }
public void AddName(string name)
{
//Ensure name is never empty string or null
if(string.IsNullOrWhiteSpace(name))
throw new ArgumentNullException("name");
members.Add(name);
}
}
You can then add more members as such:
var pg = new ProjectGroup();
pg.AddName("alice");
pg.AddName("sarah");
You can create method for member removal in the similar fashion.

C# - add attribute like '.Length' to custom class

I've playing around with a class that acts as a public interface for a private List<T> attribute. I noticed that the List<> class has an attribute Length that tells you how many elements it contains.
This is an attribute you cannot alter, and on the intellisense appears with an image of a spanner next to it. It is not a method as it does not require () after coding the name.
I've seen attributes of this type before, but never used them in my own classes. Does anybody have any idea how I can replicate Length in my custom class?
Thanks,
Mark
It's a property with no setter. If you're wrapping a List<T> you can just use it's Count as your own:
public int Count {get {return _myPrivateList.Count; } }
If you're using C# 6, you can use this:
public int Count => _myPrivateList.Count;
If you currently have a class that contains a List, then you can take advantage of the Count property already present on it by exposing a property that simply uses that :
public class YourExampleList<T>
{
// Example of your inner list
private List<T> _list { get; set; }
// Use the Count property to expose a public "Length" equivalent
public int Length { get { return _list.Count; } }
}
This is actually not a method, but a property.
So you could have define in your class
private List<string> myList = new List<string>();
public int NumberOfElements
{
get { return this.myList.Count; }
}
A normal property would be defined such as
public bool ColumnNames { get; set; }
List<T> myList = new List<T>();
Now you can create your own implementation on your custom class. Something like:
public int Length {get {return myList.Count; }}
I must admit that your question is a bit vague. It sounds like you want know how to create a read only attribute / property. This can be achieved by creating a property wrapper for a private field member of your class as follow:
class MyCustomClass
{
private int _length;
public int Length
{
get { return _length; }
}
}
Say for example you have a class like this:
public class MyClass
{
private string _str;
public MyClass()
{
_str = "Sample String";
}
public int Length
{
get
{
return _str.Length;
}
}
}
This is what's happening:
We're declaring a private field at the start of the class named _str.
In the constructor we're then assigning it a value of "Sample String".
After the constructor we're then declaring the public attribute Length of type int, and only giving it a get accessor. Like your example, this only allows the value to be read, and not set.
Within the get we then tell it to return the value of _str's length.
Using code similar to this you can implement a Length attribute for any custom class.

Designing class with fields as string arrays

I'm not sure if this is the right title, but here goes.
I have a simple class with many fields and a method that checks these fields. The class looks like below. I removed the accessors for space.
So I call SetAlarms to set the fields to later use them with method AlarmsOk() and other methods. Everything worked fine since the datatable only had one row.
Now the datatable has two rows. So I was thinking of using a struct array to store these two rows. If I continued using the class fields, I'd set them as arrays I would need to initialize each string, which means that I would need to add 100 rows, one per field. One the other hand, I can have a struct array and initialize it two length of 2 with one line.
Is this correct?
public class Alarms
{
private string[] alarm0;
private string[] alarm1;
// to Alarm99
private string[] alarm99;
public void SetAlarms(DataTable AlarmsTable)
{
int currentRow = 0;
int rowCount = AlarmsTable.Rows.Count; //AlarmsTable has 2 rows
alarm0 = new string[rowCount];
alarm1 = new string[rowCount];
// to Alarm99
alarm99 = new string[rowCount];
foreach (DataRow row in AlarmsTable.Rows)
alarm0[currentRow] = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm0"]);
alarm1[currentRow] = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm1"]);
// to Alarm99
alarm99[currentRow] = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm99"]);
currentRow++;
}
}
public bool AlarmsOk()
{
//Check if alarms are OK, return true/false
}
}
If I understand correctly, I would rather use some AlarmData class and a List instead:
public class AlarmData
{
public string Alarm0 { get; set; }
...
public string Alarm99 { get; set; }
}
public class Alarms
{
private List<AlarmData> alarmData = new List<AlarmData>();
public void SetAlarms(DataTable AlarmsTable)
{
this.alarmData.Clear();
foreach (DataRow row in AlarmsTable.Rows)
{
var newData = new AlarmData();
newData.Alarm0 = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm0"]);
...
newData.Alarm99 = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm99"]);
this.alarmData.Add(newData);
}
}
public bool AlarmsOk()
{
//Check if alarms are OK, return true/false
}
}
So you have a class that correspond to your table (and an instance in your list for each row), which is easier to read IMO.
You can use array of arrays:
private string[][] alarm;
And use it:
alarm[0][currentRow] = value;
This seems like bad design to me. Your OP suggests you are crowbarring everything into a single table.
Rather than have a single Alarms class,I think you should have a singular Alarm class. This would store information about a single alarm entity only. Then whatever the object is that actually has the alarms (say a Foo) would have a collection of Alarm objects - so something like
public class Foo
{
public List<Alarm> Alarms { get; set; }
}
On the database side you would have a Foo table and an Alarm table. Your Alarm table will have a FooID column so you can link each one back to the Foo.

Defining and using a Global Generic List in WCF Application

I am sending a few separate messages from an asp.net site to my WCF server.
These messages are coming through individually, and I need the server to pick them up, and 'stitch' them together.
What I am trying to do is put those methods in a global List, then using that list in a different class to do my bidding.
So far I have...
variables.cs
class variables
{
public static List<string> MessageStitches { get; set; }
}
Program.cs
if (!string.IsNullOrEmpty(node))
{
variables.MessageStitches.Add(node);
}
But I am getting this error:
Object reference not set to an instance of an object.
Can anyone see where I am going wrong, and how to fix it?
You have not set the variables.MessageStitches property to be a new list.
You have several options, but the best option for you is almost certainly 1 or 2.
1 - Assign a new list in the constructor of variables. However, as your list is static, this will not actually help you, as you may not have instantiated your variables class, and so your constructor will not have run. You can have a static constructor though:
class variables
{
public static List<string> MessageStitches { get; set; }
// Static constructor
static variables()
{
MessageStitches = new List<string>();
}
}
2 - Don't use auto-properties. Instead, have a backing field for your property, which is assigned a value at initialisation:
public class variables
{
private static List<string> messageStitches = new List<string>();
public static List<string> MessageStitches
{
get
{
return messageStitches;
}
set
{
messageStitches = value;
}
}
3 - Check the list before using to ensure it's not null and, if it is, assign a new list then. Again, this will not be threadsafe, unless you take steps to make it so (e.g. by entering a critical section)
if (!string.IsNullOrEmpty(node))
{
if (variables.MessageStitches == null)
{
variables.MessageStitches = new List<string>();
}
variables.MessageStitches.Add(node);
}
Define a constructor in Variable.cs like:
public variables()
{
MessageStitches = new List<string>();
}
or you can do like this :
variables.MessageStitches = new List<string>();
variables.MessageStitches.Add(node);

Class property as a collection

Greetings,
I need to include a property in my class which is a collection of System.IO.FileInfo objects. I am not really sure how to do this and how I would add and removed objects from an instance of the the class (I would assume like any other collection).
Please let me know if I need to add more information.
Thank you
Update: Am I approaching this the wrong way? I have read comments that adding to a collection which is a property is bad practice. If this is true what is good practice? I have a bunch of objects I need to store in a collection. The collection will be added to and removed from before a final action will be taken on it. Is this a correct approach or am I missing something?
using System.Collections.ObjectModel;
public class Foo
{ private Collection<FileInfo> files = new Collection<FileInfo>();
public Collection<FileInfo> Files { get { return files;} }
}
//...
Foo f = new Foo();
f.Files.Add(file);
File is a static class. So let's assume you meant FileInfo.
There are lots of ways, you can:
Expose a private field
Use Iterators
Expose a private field through a ReadOnlyCollection<>
For example,
class Foo {
public IEnumerable<FileInfo> LotsOfFile {
get {
for (int i=0; i < 100; i++) {
yield return new FileInfo("C:\\" + i + ".txt");
}
}
}
private List<FileInfo> files = new List<FileInfo>();
public List<FileInfo> MoreFiles {
get {
return files;
}
}
public ReadOnlyCollection<FileInfo> MoreFilesReadOnly {
get {
return files.AsReadOnly();
}
}
}
With this code, you can easily add to the property MoreFiles:
Foo f = new Foo();
f.MoreFiles.Add(new FileInfo("foo.txt"));
f.MoreFiles.Add(new FileInfo("BAR.txt"));
f.MoreFiles.Add(new FileInfo("baz.txt"));
Console.WriteLine(f.MoreFiles.Count);
One simple way to do this is to create a property as such (sorry for the VB.Net)
Public ReadOnly Property Files As Generic.List(Of IO.File)
GET
Return _Files
END GET
END Property
Where _Files is a private class variable of type Generic.List(Of IO.File), which holds the list of files. That will allow files to be added and removed by calling the functions of the List data type. Some people will probably say this is bad practice, and that you should never expose the collection itself, and instead recode all the necessary functions as separate parameters, which would basically just call the appropriate functions from your private collection.
I just make it either a list or dictionary. I'll show both.
class Example
{
public List<FileInfo> FileList { get; set; }
public Dictionary<string, FileInfo> Files { get; set; }
public Example()
{
FileList = new List<FileInfo>();
Files = new Dictionary<string, FileInfo>();
}
}
You would now use the property as if it were the actual List or Dictionary object.
var obj = new Example();
obj.FileList.Add(new FileInfo("file.txt")); // List<>
obj.Files.Add("file.txt", new FileInfo("file.txt")); // Dictionary<>
// also
obj.Files["file2.txt"] = new FileInfo("file2.txt"); // Dictionary<>
// fetch
var myListedFile = obj.FileList[0]; // List<>
var myFile = obj.Files["file.txt"]; // Dictionary<>
I prefer the dictionary approach.
Note that since the property is public set, you could replace the entire list or dictionary as well.
obj.Files = new Dictionary<string, FileInfo>();
// or
var otherFiles = new Dictionary<string, FileInfo>();
otherFiles["otherfile.txt"] = new FileInfo("otherfile.txt");
obj.Files = otherFiles;
If you made the property private set, then you could still call Add(), but not reassign the list or dictionary itself.

Categories

Resources