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 have a typed array MyType[] types;
and i want to make and independant copy of this array. i tried this
MyType[] types2 = new MyType[types.Length] ;
types2 = types ;
but this create a reference to the first. I then tried
Array.Copy( types , types2 , types.Length ) ;
but I have the same problem: changing a value in the first array changes the value in the copy as well.
How can I make a completely independent or deep copy of an Array, IList or IEnumerable?
Based on the first post, all he needs is this for "an independent copy of the array". Changes to the shallowCopy array itself would not appear in the types array (meaning element assignment, which really is what he showed above despite saying "deep copy"). If this suits your needs, it will have the best performance.
MyType[] shallowCopy = (MyType[])types.Clone();
He also mentions a "deep copy" which would be different for mutable types that are not recursive value-type aggregates of primitives. If the MyType implements ICloneable, this works great for a deep copy:
MyType[] deepCopy = (MyType[])Array.ConvertAll(element => (MyType)element.Clone());
For the impatient:
newarray = new List<T>(oldarray).ToArray();
Implement a clone method on MyType, using protected method MemberwiseClone (performs shallow copy) or using a deep cloning technique. You can have it implement an ICloneable then write several extensions methods that will clone the corresponsing collection.
interface ICloneable<T>
{
T Clone();
}
public static class Extensions
{
public static T[] Clone<T>(this T[] array) where T : ICloneable<T>
{
var newArray = new T[array.Length];
for (var i = 0; i < array.Length; i++)
newArray[i] = array[i].Clone();
return newArray;
}
public static IEnumerable<T> Clone<T>(this IEnumerable<T> items) where T : ICloneable<T>
{
foreach (var item in items)
yield return item.Clone();
}
}
You must do this because while a new array is created when you use Array.Copy it copies the references, not the objects referenced. Each type is responsible for copying itself.
If your type is serializable you can use serialization techniques to get a copy of your array (including deep copies of the items):
private static object GetCopy(object input)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, input);
stream.Position = 0;
return formatter.Deserialize(stream);
}
}
To use it:
MyType[] items = new MyType[2];
// populate the items in the array
MyType[] copies = (MyType[])GetCopy(items);
I wanted to do the same thing: make a copy of an array by value for things like sorting so that I could later reinitialize another temp array with the original source array. After researching this, I found this cannot be done so simply. So, I made a workaround. I will use my own code below:
string[] planetNames = new string[] { "earth", "venus", "mars" };
string[] tempNames = new string[planetNames.Length];
for (int i = 0; i < planetNames.Length; i++)
{
tempNames[i] = planetNames[i];
}
planetNames is my source array. tempNames is the array which I will later sort independently of planetNames. I have tested this and this code does not sort planetNames when I sort tempNames which is what I was attempting to achieve.
If you want to create a copy of just an array with references to objects in old array (or if you have array of value type objects), simplest solution is
var newArray = oldArray.ToArray()
If you want deep copy you should have a method which copies single object of your type (e.g. public MyType Copy(MyType obj)). Then solution will look like
var newArray = oldArray.Select(x => Copy(x)).ToArray()
I've found if you just want a simple char array copy you can trick C# into doing a copy by value using the char:
char[] newchararray = new char[desiredchararray.Length];
for (int k = 0; k < desiredchararray.Length; k++)
{
char thecharacter = newchararray[k];
newchararray[k] = thecharacter;
oldchararray[k] = oldchararray[k] + 1;
}
Seems to work for me but if anyone disagrees please let me know :)
Copying the value of the array in this case are numbers
int[] arr = { 1, 2, 3, 4, 5 };
int[] copyArr = new int[arr.Length];
for (int i = 0; i <arr.Length; i++)
{
copyArr[i]=arr[arr.Length-i-1];
}
Console.WriteLine(string.Join(" ",arr));**
I'm creating one object by using values from other object.Like that:
MAP.cs
int[][] map = {......};
Mob m = new Mob(0,0,map);
And calling Mob's class function Move()
m.Move();
Move function looks like this:
int xp = (int)Math.Floor(x / 32);
int yp = (int)Math.Floor(y / 32);
int[] result = lookForClosest(xp, yp);
this.nextX = result[1];
this.nextY = result[0];
map[this.nextY][this.nextX] = 1;
Functions are called using DispatcherTimer in another class(MainWindow)
The result of this application is that map property in MAP class is changed. The only change made should be in the Mob object's map property. Any explanation and possible fix?
Arrays are reference types, so when you call
Mob m = new Mob(0,0,map);
You are passing a reference to the array to the Mob constructor, and any changes you make to the array in the Mob class will be reflected in the source array. You can change this one of two ways:
Clone the array before passing it to the Mob class, or
Clone the array within the Mob constructor.
From a ownership perspective, the question is - should clients expect to see changes to the array, or is the array more of a "seed" input that can be modified within the class?
Also note that you have an array of arrays, so you not only need to close the "outer" array, but each of the arrays within it:
public T[][] Clone<T>(T[][] source)
{
T[][] output = new T[source.Length][];
for(int i=0; i<source.Length; i++)
output[i] = (T[])source[i].Clone();
return output;
}
or if you're comfortable with Linq:
public T[][] Clone<T>(T[][] source)
{
return source.Select(a => (T[])a.Clone()).ToArray();
}
CardDetails is a Structure.
public static void ParceIntricaciesJabber(ref CardDetails[] WhichArray)
{
WhichArray[0].ID = 50;
WhichArray[0].Type = "None";
}
In calling:
ParceIntricaciesJabber(ref OpponentCards);
After I call the function though, another Array called PlayerCards is affected in the exact same way as OpponentCards - despite being declared as two different arrays. They have the same number of elements and the same data Type, and that's it.
This probably should be obvious but i'm not seeing it. The code works in VB.NET. What am I doing wrong?
EDIT: Initialization Code:
public static class Module1{
public static CardDetails[] PlayerCards = new CardDetails[100];
public static CardDetails[] OpponentCards = new CardDetails[100];
}
And also when navigating to the Form
for (int n = 1; n <= 100; n++)
{
Module1.PlayerCards[n] = new CardDetails();
Module1.OpponentCards[n] = new CardDetails();
}
My guess is that you are sharing the reference to the arrays. Even though it is structs inside the array, the array itself is a reference type. You will need to post your array instantiation code to verify one way or the other though
I have a typed array MyType[] types;
and i want to make and independant copy of this array. i tried this
MyType[] types2 = new MyType[types.Length] ;
types2 = types ;
but this create a reference to the first. I then tried
Array.Copy( types , types2 , types.Length ) ;
but I have the same problem: changing a value in the first array changes the value in the copy as well.
How can I make a completely independent or deep copy of an Array, IList or IEnumerable?
Based on the first post, all he needs is this for "an independent copy of the array". Changes to the shallowCopy array itself would not appear in the types array (meaning element assignment, which really is what he showed above despite saying "deep copy"). If this suits your needs, it will have the best performance.
MyType[] shallowCopy = (MyType[])types.Clone();
He also mentions a "deep copy" which would be different for mutable types that are not recursive value-type aggregates of primitives. If the MyType implements ICloneable, this works great for a deep copy:
MyType[] deepCopy = (MyType[])Array.ConvertAll(element => (MyType)element.Clone());
For the impatient:
newarray = new List<T>(oldarray).ToArray();
Implement a clone method on MyType, using protected method MemberwiseClone (performs shallow copy) or using a deep cloning technique. You can have it implement an ICloneable then write several extensions methods that will clone the corresponsing collection.
interface ICloneable<T>
{
T Clone();
}
public static class Extensions
{
public static T[] Clone<T>(this T[] array) where T : ICloneable<T>
{
var newArray = new T[array.Length];
for (var i = 0; i < array.Length; i++)
newArray[i] = array[i].Clone();
return newArray;
}
public static IEnumerable<T> Clone<T>(this IEnumerable<T> items) where T : ICloneable<T>
{
foreach (var item in items)
yield return item.Clone();
}
}
You must do this because while a new array is created when you use Array.Copy it copies the references, not the objects referenced. Each type is responsible for copying itself.
If your type is serializable you can use serialization techniques to get a copy of your array (including deep copies of the items):
private static object GetCopy(object input)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, input);
stream.Position = 0;
return formatter.Deserialize(stream);
}
}
To use it:
MyType[] items = new MyType[2];
// populate the items in the array
MyType[] copies = (MyType[])GetCopy(items);
I wanted to do the same thing: make a copy of an array by value for things like sorting so that I could later reinitialize another temp array with the original source array. After researching this, I found this cannot be done so simply. So, I made a workaround. I will use my own code below:
string[] planetNames = new string[] { "earth", "venus", "mars" };
string[] tempNames = new string[planetNames.Length];
for (int i = 0; i < planetNames.Length; i++)
{
tempNames[i] = planetNames[i];
}
planetNames is my source array. tempNames is the array which I will later sort independently of planetNames. I have tested this and this code does not sort planetNames when I sort tempNames which is what I was attempting to achieve.
If you want to create a copy of just an array with references to objects in old array (or if you have array of value type objects), simplest solution is
var newArray = oldArray.ToArray()
If you want deep copy you should have a method which copies single object of your type (e.g. public MyType Copy(MyType obj)). Then solution will look like
var newArray = oldArray.Select(x => Copy(x)).ToArray()
I've found if you just want a simple char array copy you can trick C# into doing a copy by value using the char:
char[] newchararray = new char[desiredchararray.Length];
for (int k = 0; k < desiredchararray.Length; k++)
{
char thecharacter = newchararray[k];
newchararray[k] = thecharacter;
oldchararray[k] = oldchararray[k] + 1;
}
Seems to work for me but if anyone disagrees please let me know :)
Copying the value of the array in this case are numbers
int[] arr = { 1, 2, 3, 4, 5 };
int[] copyArr = new int[arr.Length];
for (int i = 0; i <arr.Length; i++)
{
copyArr[i]=arr[arr.Length-i-1];
}
Console.WriteLine(string.Join(" ",arr));**
In the following code block, why do I need to declare myData in the class, then initialize myData = new string[size] in the constructor? Why is it illegal to code private string[] myData = new string[size] ?
That is, why do I need to do:
class IntIndexer
{
private string[] myData;
public IntIndexer(int size)
{
myData = new string[size];
for (int i = 0; i < size; i++)
{
myData[i] = "empty";
}
}
}
Instead of
class IntIndexer
{
private string[] myData = new string[size];
public IntIndexer(int size)
{
for (int i = 0; i < size; i++)
{
myData[i] = "empty";
}
}
}
Because the variable "size" only exists in the constructor.
Because you do not know what size will be, or even if it exists outside the constructor.
Inline initialisers run as part of all constructors in the class. Adding another constructor without size would break your class if this were implemented, a confusing state of affairs.
Also even if the compiler were made smart enough to check for all this it would be a confusing abuse of scope. What if there were a constant field called size somewhere else in the class?
All these are reasons to not attempt to allow this sort of thing and there are precious little benefits to it so why bother.
Because size is only known to the constructor at run-time - not compile-time. If you wanted to size myData to a constant size - i.e. known at compile-time, then you could do it in the declaration:
private string[] myData = new string[1000];
or
private const int DATA_SIZE = 1000;
private string[] myData = new string[DATA_SIZE];
Because size is a parameter of the constructor and only exists within the scope of the constructor.
The issue here is one of scope. You can't reference size, a parameter of the constructor, outside the constructor because it isn't defined outside the constructor. This will give you a compile error. If the variable were defined in the object, it would be perfectly legal, but you'd be dependent on the order of initialization as to whether you would get the effect you intended. If the initializer for the variable were run before the initializer for the array, then it might work. IMO, you're better off doing the initialization in the constructor because that way you define the order of execution and know what will happen, when.
Because you don't know the size until the constructor is called. The following field definition is fine:
private string[] myData = new string[100];
you cannot do that for one reason: How would the compiler know how big size is at compile time?
if you want to initialise an array with a runtime-variable size, you must initialise it within a runtime method when the variable has a value!
Because if you try to do in this way
class IntIndexer
{
private string[] myData = new string[size];
public IntIndexer(int size)
{
for (int i = 0; i < size; i++)
{
myData[i] = "empty";
}
}
}
you will get compilation error
The name 'size' does not exist in the current context.
beacuse at this point
private string[] myData = new string[size];
size is not yet declared.
And if you will write in this way from where you will get the value of size as your objective i think will be to make it flexible and let the instance do that for you that's why your objective can be done by this
class IntIndexer
{
private string[] myData;
public IntIndexer(int size)
{
myData = new string[size];
for (int i = 0; i < size; i++)
{
myData[i] = "empty";
}
}
}
ie you will be setting that size like this
IntIndexer instance = new IntIndexer(100);