Given a class:
class clsPerson { public int x, y; }
Is there some way to create an array of these classes with each element initialized to a (default) constructed instance, without doing it manually in a for loop like:
clsPerson[] objArr = new clsPerson[1000];
for (int i = 0; i < 1000; ++i)
objArr[i] = new clsPerson();
Can I shorten the declaration and instantiation of an array of N objects?
The constructor must be run for every item in the array in this scenario. Whether or not you use a loop, collection initializers or a helper method every element in the array must be visited.
If you're just looking for a handy syntax though you could use the following
public static T[] CreateArray<T>(int count) where T : new() {
var array = new T[count];
for (var i = 0; i < count; i++) {
array[i] = new T();
}
return array;
}
clsPerson[] objArary = CreateArray<clsPerson>(1000);
You must invoke the constructor for each item. There is no way to allocate an array and invoke your class constructors on the items without constructing each item.
You could shorten it (a tiny bit) from a loop using:
clsPerson[] objArr = Enumerable.Range(0, 1000).Select(i => new clsPerson()).ToArray();
Personally, I'd still allocate the array and loop through it (and/or move it into a helper routine), though, as it's very clear and still fairly simple:
clsPerson[] objArr = new clsPerson[1000];
for (int i=0;i<1000;++i)
clsPerson[i] = new clsPerson();
If it would make sense to do so, you could change class clsPerson to struct Person. structs always have a default value.
Related
I'm looking for a way to replace some of my List objects with arrays in my project to boost performance. The reasoning is that the List I would replace do not change size often (sometimes only once), so it would make sense to swap them out with arrays. Also, I would like to prevent allocations on the heap as much as possible.
So my idea is to create a struct (ArrayStruct) with two members "Count" and "Array". The struct would have some functions to add/remove/get/set/ect... elements in the array. The count would keep count of the elements that are usable in the array, and the array would only increase in size, never decrease.
Note that this is for a very particular case because I know the array size won't be very big.
The main problem I have is when I pass the reference to an already existing ArrayStruct object (named a in the example) to another (named b in the example) - I can edit the array in it, but once I resize it in a, I get an out of range exception in b. Is this because of the way I'm updating the reference via System.Array.Resize, so that the object b somehow does not attribute this change?
The only thing I could come up with as an idea was trying to override the assignment operator so that it would create a new array on assignment... but obviously that does not work.
My ArrayStruct
public struct ArrayStruct<T>
{
[SerializeField] private int m_Count;
[SerializeField] private T[] m_Array;
public int Count => m_Count;
public void Initialize(int startSize)
{
m_Count = 0;
m_Array = new T[startSize];
}
public T GetAt(int index)
{
return m_Array[index];
}
public void SetAt(int index, T newValue)
{
m_Array[index] = newValue;
}
public void Add(T newElement)
{
if (m_Array == null) {
m_Array = new T[1];
} else if (m_Array.Length == m_Count) {
System.Array.Resize(ref m_Array, m_Count + 1);
}
m_Array[m_Count] = newElement;
m_Count++;
}
public void Remove(T element)
{
for (int i = 0; i < m_Count; ++i) {
if (!element.Equals(m_Array[i])) {
continue;
}
for (int j = index; j < m_Count - 1; ++j) {
m_Array[j] = m_Array[j + 1];
}
m_Count--;
m_Array[m_Count] = default(T);
break;
}
}
//Trying to overload the = operating by creating a auto cast, this gives a compile error
/*public static implicit operator ArrayStruct<T>(ArrayStruct<T> otherArray)
{
var newArray = new ArrayStruct<T>();
newArray.m_Count = otherArray.Count;
newArray.m_Array = new T[otherArray.Length];
otherArray.m_Array.CopyTo(newArray.m_Array);
return newArray;
}*/
An example showcasing the problem
var a = new ArrayStruct<string>()
a.Add("hello");
var b = a;
print (b.GetAt(0)); //"hello"
a.SetAt(0, "new value for a");
print(b.GetAt(0));//"new value for a" , changing a changed b because the array is the same in both, this is bad
a.Add("resizing array");
print (b.GetAt(1)); //"Out of range exception" , because the array was resized for a but not for b therefore the connection broke
So do any of you have an idea of how I could make a new copy the array when I assign the struct to another variable?
Of course, I know I could use a function to do something like so
b = new ArrayStruct(a);
But I want it to be implicit. Or if there was a way to prevent assignments that would also work for me.
var a = new ArrayStruct();//let this work
var b = a; //Prevent this from happening
If you have any other solutions for replacing Lists with arrays conveniently please let me know
So do any of you have an idea of how I could make a new copy the array when I assign the struct to another variable? Of course, I know I could use a function to do something like so b = new ArrayStruct(a); But I want it to be implicit.
You can't do that. If a is a struct and you execute var b = a, then it will always just set b to a shallow copy of a; there's no way to change that behavior.
Doing something like b = new ArrayStruct(a) is the best you can do.
You're not understanding what the "=" operator is doing there. Objects are defined by reference, meaning when you write var b = a; you are actually asking for what you wish to avoid to happen, that is - object "b", pointing to the same object, which is "a".
You're passing the object "b" to point to the reference of object "a", which object holds the address to the object in question you defined, using the new keyword var a = new ArrayStruct<string>()
Your operator overloading does not work because you can't use it for conversions of the same type as the class you're writing the operator in. You'd either have to make a separate object (class), which would defeat the point you're trying to fix, or pass the m_array instead: public static implicit operator ArrayStruct<T>(T[] array)
You can also do something like this:
public static ArrayStruct<T> CopyFrom (ArrayStruct<T> array)
{
var newArray = new ArrayStruct<T>();
newArray.m_Array = new T[array.Count + 1];
newArray.Count = array.Count;
Array.Copy(array.m_Array, 0, newArray.m_Array, 0, array.m_Array.Length);
return newArray;
}
Now it should work exactly as you wanted.
var a = new ArrayStruct<string>();
a.Add("hello");
var b = ArrayStruct<string>.CopyFrom(a);
a.SetAt(0, "new value for a");
a.Add("resizing array");
Console.WriteLine(b.Count); // b returns 1
Console.WriteLine(a.Count); // a returns 2
As to why your index was going out of bounds, i.e it did not preserve the reference found in "a", this is all in correlation with references, yet again.
In the following code System.Array.Resize(ref m_Array, Count + 1); you're changing the reference found for object m_array in "a", when you're adding the new element with the line a.Add("resizing array");. That essentially means that your "a" object's m_array (which is another object of type array[]) is now pointing to a new object (of type array[]), which is of a new size.
Okay, but object "a" is now using the new reference, whilst object "b" is still using the old one. m_array in object "b" only has a single element, while the new m_array object in "a" has the newly added element "resizing array", along with any previously added ones.
I believe that's how System.Array.Resize works? Edit me if I'm wrong.
Below is a resource explaining how to do a deep cloning of an object, if that's what you truly wish to do (i.e create a completely new copy of an object, as well as any other objects inside)
Deep cloning of objects
I am trying to store each iteration of an array as it is being sorted through. For some reason the jagged array I return just becomes an array of the final sorted array. My code is below I cannot figure out why any help would be really appreciated. Thanks.
namespace SortingUI.Utils
{
public class Sorting
{
public static int[][] SortInt(int[] originalArray)
{
int length = originalArray.Length;
int tempVal, smallest;
int[][] iterations = new int[length-1][];
for (int i = 0; i < length - 1; i++)
{
smallest = i;
for (int j = i + 1; j < length; j++)
{
if (originalArray[j] < originalArray[smallest])
{
smallest = j;
}
}
tempVal = originalArray[smallest];
originalArray[smallest] = originalArray[i];
originalArray[i] = tempVal;
iterations[i] = originalArray;
}
return iterations;
}
}
}
If i understand your problem, the reason you are getting the same values (and not a snapshot) is because you are storing a reference to the array, and not a copy of the values themselves.
Arrays are reference types, so when you assign them to another variable you are only copying reference and not the contents. If you change the contents, all the references will reflect that
You can make use of Array.Copy to copy the values at the point in time from the originalArray
...
var tempVal = originalArray[smallest];
originalArray[smallest] = originalArray[i];
originalArray[i] = tempVal;
// Create some new memory
iterations[i] = new int[originalArray.Length];
// Copy the contents
Array.Copy(originalArray, iterations[i], originalArray.Length);
Note this is totally untested and i have no idea if the rest of your code is working as intended
Additional Resources
Array.Copy Method
Copies a range of elements in one Array to another Array and performs
type casting and boxing as required.
Arrays (C# Programming Guide)
Array types are reference types derived from the abstract base type Array. Since this type implements IEnumerable and IEnumerable,
you can use foreach iteration on all arrays in C#.
What I'm trying to do is without generic types is simple.
SomeType[] s = new SomeType[5];
for(int i = 0; i < 5: i++){
s[i]= new SomeType();
}
Using generics this is what I have so far.
private static T TypeMapper<T>(dynamic handle) {
if (typeof(T).IsArray)
{
Type elementType = typeof(T).GetElementType();
int arrayLength = handle.Length;
Array array = Array.CreateInstance(elementType, arrayLength);
//??? How to get the type of an generic array element
Type typeOfthis = typeof(array[0]).GetElementType();
for (int i = 0; i < arrayLength; i++)
{
//??? How to create an instance from it.
array[i] = new typeOfthis ();
}
T obj = (T)(object)array;
return obj;
}
else
{}
Then calling the TypeMapper function with.
dynamic t = new TextSpan[4];
var result = TypeMapper<TextSpan[]>(t)
How can I get the type of an generic array element.
Type typeOfthis = typeof(array[0]).GetElementType();//Not Working
And how to create an instance from it.
array[i] = new typeOfthis ();
Your help is highly appreciated.
The Solution of Rubidium 37 was marked as correct
Type typeofitem = array.GetType().GetElementType();
instead of
Type typeOfthis = typeof(array[0]).GetElementType();
and
array.SetValue(Activator.CreateInstance(typeofitem), i);
instead of
array[i] = new typeOfthis ();
Thanks also for the other solutions here, but they quite missing the point that I can pass SomeType[] or SomeType as T to TypeMapper<T>(dynamic handle).
Then I can then derive from the type if it is an array or not and process the handle as needed.
offtopic
The long breath reason behind it is to marshal javascript types from v8 used by the v8dotnet wrapper which returns objects which have an equal behavior like dynamic objects.Instead of explaining what an InternalHandle handle is I reduced it to dynamic so that it is comprehensible.
When you have an array element, you have an object, that can be a different type from other array elements (like a derived type).
Then you can get the type of a single element array as you do for any standalone object.
You should replace
Type typeOfthis = typeof(array[0]).GetElementType();
with
Type typeOfthis = array[0].GetType();
Whereas, when you want create an object of any type, you can simply using Activator.CreateInstance or retrieve one ConstructorInfo from the Type.
Replace
array[i] = new typeOfthis ();
with
array[i] = Activator.CreateInstance(typeOfthis);
Just for you yo know..
- Remember that Activator.CreateInstance will try to call a parameterless constructor of the type you pass to it, then that type need to have such a constructor.
- The object you create need to be compatible with the array's Element type (assignable to it, like a derived class).
- If you know in advance that all elements of the array are (or should be) of the same type, then you don't need to get the type for each element; instead, typeof(T).GetElementType() should be enough.
- If the element type is a class and you don't need to assign concrete values because they are assigned later, or you know that the elementi type is struct, then you don't need to fill the array.
A part of that details, if you want to create a new array, given its length and the (concrete) type of its elements, you can try one of the following:
public static Array CreateAndFillArray(Type type, int length)
{
var result = Array.CreateInstance(type, length);
for (int ixItem = 0; ixItem < result.Length; ixItem++)
result.SetValue(Activator.CreateInstance(type), ixItem);
return result;
}
public static T[] CreateAndFillArray<T>(int length)
{
var type = typeof(T);
var result = new T[length];
for (int ixItem = 0; ixItem < result.Length; ixItem++)
result[ixItem] = (T)Activator.CreateInstance(type);
return result;
}
public static T[] CreateAndFillArray<T>(int length)
where T : new()
{
var result = new T[length];
for (int ixItem = 0; ixItem < result.Length; ixItem++)
result[ixItem] = new T();
return result;
}
Regards,
Daniele.
You need to learn something more about generics (and generalization in general). If you want to fill an array with default instances of a type, you can use this:
void ConstructAll<T>(T[] array) where T : new()
{
for (var i = 0; i < array.Length; i++)
{
array[i] = new T();
}
}
However, this doesn't really look like a good idea. What problem are you trying to solve? And why would you think using dynamic is a good solution?
I have 3-dimensional array in my programm. I want to debug values in it and I put this array into another array, in which I want to find difference.
I tried this:
Weights weights = new Weights(); // init inside
List<Weights> weightsDebug = new List<Weigts>();
weightsDebug.Add(weights); // I'd put first weigths into the list
for(int i = 0; i < 100; i++) {
// do some bad things with weights;
weightsDebug.Add(weights);
}
After that, I'd got same values in weights in all 99 elements of weigthsDebug. I'd tried to debug and I'd realised, that weigts array is being changed. I understood that problem is in the reference (copy by link, not by value) – all pushed to weightsDebug array elements are linked with weights in main loop.
I'd googled a bit and found some ways how to copy 1-dimensional array. I'tried next:
I added Clone method to my Weights class:
double[][][] values;
public Weights Clone() {
Weights clone = new Weights();
clone.values = (double[][][]) this.values.Clone();
return clone;
}
public Weights()
{
Console.WriteLine("Constructor WITHOUT arguments fired");
}
Now I am doing so when copy weights:
Weights weights = new Weights(); // init inside
List<Weights> weightsDebug = new List<Weigts>();
weightsDebug.Add(weights); // I'd put first weigths into the list
for(int i = 0; i < 100; i++) {
// do some bad things with weights;
Weights weightsClone = weights.Clone();
weightsDebug.Add(weightsClone);
}
And I am still getting last changed value in whole debug array. How I can correct it?
What you really are looking for here is deep cloning rather than the current shallow cloning that you are implementing.
A long time ago, we realized that by making the classes Serializable, we could use the .Net serialization classes to quickly, easily, and correctly make deep clones of any object.
Here is a method that we use for this deep cloning (there is also a SilverLight variation that uses DataContractSerializer):
/// <summary>
/// This method clones all of the items and serializable properties of the current collection by
/// serializing the current object to memory, then deserializing it as a new object. This will
/// ensure that all references are cleaned up.
/// </summary>
/// <returns></returns>
/// <remarks></remarks>
public T CreateSerializedCopy<T>(T oRecordToCopy)
{
// Exceptions are handled by the caller
if (oRecordToCopy == null)
{
return default(T);
}
if (!oRecordToCopy.GetType().IsSerializable)
{
throw new ArgumentException(oRecordToCopy.GetType().ToString() + " is not serializable");
}
var oFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var oStream = new MemoryStream())
{
oFormatter.Serialize(oStream, oRecordToCopy);
oStream.Position = 0;
return (T)oFormatter.Deserialize(oStream);
}
}
To use this, first ensure the Weights class is tagged with the Serializable attribute:
[Serializable]
public class Weights
Then you can clone as needed:
var weights = new List<Weights>();
weights.Add(new Weights());
var debugWeights = CreateSerializedCopy<List<Weights>>(weights);
if (debugWeights[0] == weights[0])
{
System.Diagnostics.Debug.WriteLine("Did not serialize correctly");
}
The problem here is that you don't have a true multi-dimensional array, where there's just a single object. You have a "jagged" multi-dimensional array, where the object is actually an array of arrays of arrays. This means that to clone the object, you need to do more work:
clone.values = new double[values.Length][][];
for (int i = 0; i < values.Length; i++)
{
clone.values[i] = new double[values[i].Length][];
for (int j = 0; j < values[i].Length; j++)
{
clone.values[i][j] = (double[])values[i][j].Clone();
}
}
I have:
public static BlockQuadrant[] EditModeBlocks = new BlockQuadrant[9];
but when I try to use them I get a null value exception, and apparently all of the values are equal to null. I thought this was a value inside my BlockQuadrant class, but I defined everything in the constructor. If this is the case, is there a way I can make it fill up the array with actual instances of BlockQuadrant instead of null values?
When you construct an array of reference objects, it constructs only an array, not the objects inside it. You need to initialize the individual objects by calling constructors.
You can take a shortcut using LINQ, like this:
public static BlockQuadrant[] EditModeBlocks = Enumerable
.Range(0, 9)
.Select(i => new BlockQuadrant())
.ToArray();
Do you have a problem with looping through your array and newing the elements?
for (int ii = 0; ii < EditModeBlocks.Length; ii++)
{
EditModeBlocks[ii] = new BlockQuadrant();
}
With your initial statement, you've created an array with default values. For reference types, the default value is null.
You will have to instantiate the each element in array before you use as the array contains null in its element.
public static BlockQuadrant[] EditModeBlocks = new BlockQuadrant[9];
In some static method use loop to instantiate them.
private static someMethod()
{
for (int i = 0; i < EditModeBlocks.Length; i++)
{
EditModeBlocks[i] = new BlockQuadrant();
}
}