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
Related
I'm having a problem in Unity with C#, I'm trying to create a List or Array that has all the information I need.
0000, 0001,0002, etc.
I want to put this into an List/Array and use this information to instantiate a model on a character selection screen. However, this is the part of code where everything starts to get messed up.
I'm just trying to read out the numbers and add them into the list.
void Start () {
gestureListener = this.GetComponent<GestureListener>();
for (int i = 0; i < numberOfModels; i++) {
string b = i.ToString("0000");
List<string> mylist = new List<string>(new string[b]);
Debug.Log (mylist);
break;
}
}
I get this error:
error CS0029: Cannot implicitly convert type `string' to `int'
The error happens on line 5, but to me this seems an to be an irreplaceable line...
The variable B is a string so I wouldn't know why the lists sees it as an int.
Please let me know if you can help, much appreciated!
If you are trying to instantiate a list to then add elements to this list then you got it wrong. You are currently instantiating a new list with just one element every time you iterate. In other words, you are not putting the list to use, you are just creating a new one every time you loop.
Create your List of Strings outside the loop then add to it from inside the loop.
You should have something like this to populate the list.
void Start()
{
List<string> mylist = new List<string>();
gestureListener = this.GetComponent<GestureListener>();
for (int i = 0; i < numberOfModels; i++) {
string b = i.ToString("0000");
myList.Add(b);
Debug.Log (mylist);
break;
}
}
With that said, at the end of your for-loop your myList will have a collection of models per say. You can then iterate that collection to see all the elements you have pushed.
foreach(var item in mylist)
{
//Do whatever with each Item.
}
If you need more examples, take a look at DotNetPerls List Examples
and this video example with Unity in mind.
void Start () {
gestureListener = this.GetComponent<GestureListener>();
List<string> myList = new List<string>();
for (int i = 0; i < numberOfModels; i++) {
string b = i.ToString("0000");
myList.Add(b);
Debug.Log (mylist);
break;
}
//myList is populated with all the numberOfModels here.
}
Don't create a new list inside the loop. The way you are doing it now, you are trying to create a new list (which you throw away anyway), that has progressively larger empty string arrays. For example with a numberOfModels of 100, you would have 100! empty string elements in the list (if you saved it).
Just create a list outside of the for loop, and add the string b to the list inside the loop.
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.
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-
}
}
}
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.
}
}
.NET offers a generic list container whose performance is almost identical (see Performance of Arrays vs. Lists question). However they are quite different in initialization.
Arrays are very easy to initialize with a default value, and by definition they already have certain size:
string[] Ar = new string[10];
Which allows one to safely assign random items, say:
Ar[5]="hello";
with list things are more tricky. I can see two ways of doing the same initialization, neither of which is what you would call elegant:
List<string> L = new List<string>(10);
for (int i=0;i<10;i++) L.Add(null);
or
string[] Ar = new string[10];
List<string> L = new List<string>(Ar);
What would be a cleaner way?
EDIT: The answers so far refer to capacity, which is something else than pre-populating a list. For example, on a list just created with a capacity of 10, one cannot do L[2]="somevalue"
EDIT 2: People wonder why I want to use lists this way, as it is not the way they are intended to be used. I can see two reasons:
One could quite convincingly argue that lists are the "next generation" arrays, adding flexibility with almost no penalty. Therefore one should use them by default. I'm pointing out they might not be as easy to initialize.
What I'm currently writing is a base class offering default functionality as part of a bigger framework. In the default functionality I offer, the size of the List is known in advanced and therefore I could have used an array. However, I want to offer any base class the chance to dynamically extend it and therefore I opt for a list.
List<string> L = new List<string> ( new string[10] );
I can't say I need this very often - could you give more details as to why you want this? I'd probably put it as a static method in a helper class:
public static class Lists
{
public static List<T> RepeatedDefault<T>(int count)
{
return Repeated(default(T), count);
}
public static List<T> Repeated<T>(T value, int count)
{
List<T> ret = new List<T>(count);
ret.AddRange(Enumerable.Repeat(value, count));
return ret;
}
}
You could use Enumerable.Repeat(default(T), count).ToList() but that would be inefficient due to buffer resizing.
Note that if T is a reference type, it will store count copies of the reference passed for the value parameter - so they will all refer to the same object. That may or may not be what you want, depending on your use case.
EDIT: As noted in comments, you could make Repeated use a loop to populate the list if you wanted to. That would be slightly faster too. Personally I find the code using Repeat more descriptive, and suspect that in the real world the performance difference would be irrelevant, but your mileage may vary.
Use the constructor which takes an int ("capacity") as an argument:
List<string> = new List<string>(10);
EDIT: I should add that I agree with Frederik. You are using the List in a way that goes against the entire reasoning behind using it in the first place.
EDIT2:
EDIT 2: What I'm currently writing is a base class offering default functionality as part of a bigger framework. In the default functionality I offer, the size of the List is known in advanced and therefore I could have used an array. However, I want to offer any base class the chance to dynamically extend it and therefore I opt for a list.
Why would anyone need to know the size of a List with all null values? If there are no real values in the list, I would expect the length to be 0. Anyhow, the fact that this is cludgy demonstrates that it is going against the intended use of the class.
Create an array with the number of items you want first and then convert the array in to a List.
int[] fakeArray = new int[10];
List<int> list = fakeArray.ToList();
If you want to initialize the list with N elements of some fixed value:
public List<T> InitList<T>(int count, T initValue)
{
return Enumerable.Repeat(initValue, count).ToList();
}
Why are you using a List if you want to initialize it with a fixed value ?
I can understand that -for the sake of performance- you want to give it an initial capacity, but isn't one of the advantages of a list over a regular array that it can grow when needed ?
When you do this:
List<int> = new List<int>(100);
You create a list whose capacity is 100 integers. This means that your List won't need to 'grow' until you add the 101th item.
The underlying array of the list will be initialized with a length of 100.
This is an old question, but I have two solutions. One is fast and dirty reflection; the other is a solution that actually answers the question (set the size not the capacity) while still being performant, which none of the answers here do.
Reflection
This is quick and dirty, and should be pretty obvious what the code does. If you want to speed it up, cache the result of GetField, or create a DynamicMethod to do it:
public static void SetSize<T>(this List<T> l, int newSize) =>
l.GetType().GetField("_size", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(l, newSize);
Obviously a lot of people will be hesitant to put such code into production.
ICollection<T>
This solution is based around the fact that the constructor List(IEnumerable<T> collection) optimizes for ICollection<T> and immediately adjusts the size to the correct amount, without iterating it. It then calls the collections CopyTo to do the copy.
The code for the List<T> constructor is as follows:
public List(IEnumerable<T> collection) {
....
ICollection<T> c = collection as ICollection<T>;
if (collection is ICollection<T> c)
{
int count = c.Count;
if (count == 0)
{
_items = s_emptyArray;
}
else {
_items = new T[count];
c.CopyTo(_items, 0);
_size = count;
}
}
So we can completely optimally pre-initialize the List to the correct size, without any extra copying.
How so? By creating an ICollection<T> object that does nothing other than return a Count. Specifically, we will not implement anything in CopyTo which is the only other function called.
private struct SizeCollection<T> : ICollection<T>
{
public SizeCollection(int size) =>
Count = size;
public void Add(T i){}
public void Clear(){}
public bool Contains(T i)=>true;
public void CopyTo(T[]a, int i){}
public bool Remove(T i)=>true;
public int Count {get;}
public bool IsReadOnly=>true;
public IEnumerator<T> GetEnumerator()=>null;
IEnumerator IEnumerable.GetEnumerator()=>null;
}
public List<T> InitializedList<T>(int size) =>
new List<T>(new SizeCollection<T>(size));
We could in theory do the same thing for AddRange/InsertRange for an existing array, which also accounts for ICollection<T>, but the code there creates a new array for the supposed items, then copies them in. In such case, it would be faster to just empty-loop Add:
public void SetSize<T>(this List<T> l, int size)
{
if(size < l.Count)
l.RemoveRange(size, l.Count - size);
else
for(size -= l.Count; size > 0; size--)
l.Add(default(T));
}
Initializing the contents of a list like that isn't really what lists are for. Lists are designed to hold objects. If you want to map particular numbers to particular objects, consider using a key-value pair structure like a hash table or dictionary instead of a list.
You seem to be emphasizing the need for a positional association with your data, so wouldn't an associative array be more fitting?
Dictionary<int, string> foo = new Dictionary<int, string>();
foo[2] = "string";
The accepted answer (the one with the green check mark) has an issue.
The problem:
var result = Lists.Repeated(new MyType(), sizeOfList);
// each item in the list references the same MyType() object
// if you edit item 1 in the list, you are also editing item 2 in the list
I recommend changing the line above to perform a copy of the object. There are many different articles about that:
String.MemberwiseClone() method called through reflection doesn't work, why?
https://code.msdn.microsoft.com/windowsdesktop/CSDeepCloneObject-8a53311e
If you want to initialize every item in your list with the default constructor, rather than NULL, then add the following method:
public static List<T> RepeatedDefaultInstance<T>(int count)
{
List<T> ret = new List<T>(count);
for (var i = 0; i < count; i++)
{
ret.Add((T)Activator.CreateInstance(typeof(T)));
}
return ret;
}
You can use Linq to cleverly initialize your list with a default value. (Similar to David B's answer.)
var defaultStrings = (new int[10]).Select(x => "my value").ToList();
Go one step farther and initialize each string with distinct values "string 1", "string 2", "string 3", etc:
int x = 1;
var numberedStrings = (new int[10]).Select(x => "string " + x++).ToList();
string [] temp = new string[] {"1","2","3"};
List<string> temp2 = temp.ToList();
After thinking again, I had found the non-reflection answer to the OP question, but Charlieface beat me to it. So I believe that the correct and complete answer is https://stackoverflow.com/a/65766955/4572240
My old answer:
If I understand correctly, you want the List<T> version of new T[size], without the overhead of adding values to it.
If you are not afraid the implementation of List<T> will change dramatically in the future (and in this case I believe the probability is close to 0), you can use reflection:
public static List<T> NewOfSize<T>(int size) {
var list = new List<T>(size);
var sizeField = list.GetType().GetField("_size",BindingFlags.Instance|BindingFlags.NonPublic);
sizeField.SetValue(list, size);
return list;
}
Note that this takes into account the default functionality of the underlying array to prefill with the default value of the item type. All int arrays will have values of 0 and all reference type arrays will have values of null. Also note that for a list of reference types, only the space for the pointer to each item is created.
If you, for some reason, decide on not using reflection, I would have liked to offer an option of AddRange with a generator method, but underneath List<T> just calls Insert a zillion times, which doesn't serve.
I would also like to point out that the Array class has a static method called ResizeArray, if you want to go the other way around and start from Array.
To end, I really hate when I ask a question and everybody points out that it's the wrong question. Maybe it is, and thanks for the info, but I would still like an answer, because you have no idea why I am asking it. That being said, if you want to create a framework that has an optimal use of resources, List<T> is a pretty inefficient class for anything than holding and adding stuff to the end of a collection.
A notice about IList:
MSDN IList Remarks:
"IList implementations fall into three categories: read-only, fixed-size, and variable-size. (...). For the generic version of this interface, see
System.Collections.Generic.IList<T>."
IList<T> does NOT inherits from IList (but List<T> does implement both IList<T> and IList), but is always variable-size.
Since .NET 4.5, we have also IReadOnlyList<T> but AFAIK, there is no fixed-size generic List which would be what you are looking for.
This is a sample I used for my unit test. I created a list of class object. Then I used forloop to add 'X' number of objects that I am expecting from the service.
This way you can add/initialize a List for any given size.
public void TestMethod1()
{
var expected = new List<DotaViewer.Interface.DotaHero>();
for (int i = 0; i < 22; i++)//You add empty initialization here
{
var temp = new DotaViewer.Interface.DotaHero();
expected.Add(temp);
}
var nw = new DotaHeroCsvService();
var items = nw.GetHero();
CollectionAssert.AreEqual(expected,items);
}
Hope I was of help to you guys.
A bit late but first solution you proposed seems far cleaner to me : you dont allocate memory twice.
Even List constrcutor needs to loop through array in order to copy it; it doesn't even know by advance there is only null elements inside.
1.
- allocate N
- loop N
Cost: 1 * allocate(N) + N * loop_iteration
2.
- allocate N
- allocate N + loop ()
Cost : 2 * allocate(N) + N * loop_iteration
However List's allocation an loops might be faster since List is a built-in class, but C# is jit-compiled sooo...