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.
Related
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.
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);
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);
I have this piece of code:
public List<IVehicle> Vehicles { get; private set; }
My question is even though i am using a private set, why i can still add values to this list.
With private Set, you can't set the list to some new list from outside of your class. For example if you have a this list in a class:
class SomeClass
{
public List<IVehicle> Vehicles { get; private set; }
}
then while using:
SomeClass obj = new SomeClass();
obj.Vehicles = new List<IVehicle>(); // that will not be allowed.
// since the property is read-only
It doesn't prevent you assessing the Add method on the list. e.g.
obj.Vehicles.Add(new Vehicle()); // that is allowed
To return a Read-Only list you may look into List.AsReadOnly Method
Because private set; will not allow you to set list directly but you still can call methods of this list as it is using getter. You may want to use next:
//use this internally
private List<IVehicle> _vehicles;
public ReadOnlyCollection<IVehicle> Vehicles
{
get { return _vehicles.AsReadOnly(); }
}
.Add() is a function on the class List<> so after you get the list you can call the function. You can't replace the list with another one.
You could return an IEnumerable<IVehicle> that would make the list (sortof) readonly.
Calling .AsReadOnly() on the list would result in a really readonly list
private List<IVehicle> vehicles;
public IEnumerable<IVehicle> Vehicles
{
get { return vehicles.AsReadOnly(); }
private set { vehicles = value; }
}
When use use a private set what that means is that the property itself is un-setable from outside the class, not that it's methods are not available, and List<T>.Add() is only a method that the compiler knows nothing about.
By example:
public class VehicleContainer{
public List<IVehicle> Vehicles { get; private set; }
...
}
....
VehicleContainer vc = new VehicleContainer();
vc.Vehicles = new List<IVehicle>() // this is an error, because of the private set
int x = vc.Vehicles.Count; // this is legal, property access
vc.Vehicles.Add(new Vehicle()); //this is legal, method call
Take a look at this question, where use of the ReadOnlyCollection class is explained in the case when you want to restrict access to the collection itself, as well as the reference to the collection.
Getters and setters works on instances; not on properties of instances. An example;
Vehicles = new List<IVehicle>(); //// this is not possible
but if there is an instance it is possible to change its properties.
You can only instantiate it inside the containing class / struct of the List<IVehicle>. But once you have an instance, you can add items to it even outside, since the object is publicly visible.
I want to create a dictionary from a settings file that is formatted as a list of strings "somekey = somevalue". I then want this dictionary of keys and values, generated by one class, to be available to other classes in my program, so I don't have to refer back to the external file every time I want to use the settings in another class.
I've figured out the first part, creating a class that can read an external file and convert the list of strings into a dictionary, but I can't figure out how to make the dictionary data created by the file-reading class available to other classes in the same namespace.
A little different approach would be to use an extension method, my example is rather basic but it works perfectly
using System.Collections.Generic;
namespace SettingsDict
{
class Program
{
static void Main(string[] args)
{
// call the extension method by adding .Settings();
//Dictionary<string, string> settings = new Dictionary<string, string>().Settings();
// Or by using the property in the Constants class
var mySettings = Constants.settings;
}
}
public class Constants
{
public static Dictionary<string, string> settings
{
get
{
return new Dictionary<string, string>().Settings();
}
}
}
public static class Extensions
{
public static Dictionary<string, string> Settings(this Dictionary<string, string> myDict)
{
// Read and split
string[] settings = System.IO.File.ReadAllLines(#"settings.txt");
foreach (string line in settings)
{
// split on =
var split = line.Split(new[] { '=' });
// Break if incorrect lenght
if (split.Length != 2)
continue;
// add the values to the dictionary
myDict.Add(split[0].Trim(), split[1].Trim());
}
return myDict;
}
}
}
Contents of settings.txt
setting1=1234567890
setting2=hello
setting3=world
And the result
You should of course extend this with your own protective features and similar. This is an alternative approach but using extension methods is not that bad. The functionality in the Extensions class can also be implemented directly in the property method in the Constants class. I did that for the fun of it :)
Just make the class that constins the dictoionary public and the dictionary in that class static, so
public class MyClass
{
// ...
public static Dictionary<string, string> checkSumKeys { get; set; }
// ...
}
call this like
// ...
foreach (KeyValuePair<string, string> checkDict in MyClass.checkSumKeys)
// Do stuff...
Or, if the dictionary is not made static you will have to instantiate the class
public class MyClass
{
// ...
public Dictionary<string, string> checkSumKeys { get; set; }
// ...
}
call this like
MyClass myclass = new MyClass();
foreach (KeyValuePair<string, string> checkDict in myClass.checkSumKeys)
// Do stuff...
I hope this helps.
Im not really sure what your getting at here. Cant you simply make the dictionary a public property of that class?
Ok one option is to use a public property and then create one instance of that class when you initialise your application (this will populate your dictionary if you make it populate in your classes constructor) and then you can pass that same instance into functions or class constructors without having to read the external file again.
public class ReadFileClass
{
//Can be replaced with auto property
public Dictionary<string, string> Settings
{
Get{return Settings}
Set{Settings = value}
}
public ReadFileClass()
{
//In this constructor you run the code to populate the dictionary
ReadFile();
}
//Method to populate dictionary
private void ReadFile()
{
//Do Something
//Settings = result of doing something
}
}
//First class to run in your application
public class UseFile
{
private ReadFileClass readFile;
public UseFile()
{
//This instance can now be used elsewhere and passed around
readFile = new ReadFileClass();
}
private void DoSomething()
{
//function that takes a readfileclass as a parameter can use without making a new instance internally
otherfunction(readFileClass);
}
}
By doing the above you can use just one instantiation of an object to populate the settings dictionary and then simply pass it around. I have used this method many times to avoid making multiple round trips to a database or a file that can have costly performance impact. If you want to use the class containing the settings in another file other than the one that instantiates it you simply makes the classes constructor take it as a parameter.