Using ConvertAll to conver to array of objects - c#

Am I misunderstanding what ConvertAll does or just not understanding something, because I took it to be change the type and not just cast.
So I'm wondering how a StringBuilder (or any class) can be converted to another base class (or in this case object) and still keep its data and type.
StringBuilder[] y = new StringBuilder[] { new StringBuilder("a"), new StringBuilder("b"), new StringBuilder("c") };
object[] objectArray1 = Array.ConvertAll<StringBuilder, object>(y, (x2) => (object)x2);
In the above, the new array is of objects, but still contains StringBuilder items. I thought the new array would be of the new type, so essentially lose all the original data, e.g. converting from int to string via a conversion would give you a brand new array of strings.
As in,
string[] array2 = Array.ConvertAll(array1,
element => element.ToString());
Would give you a new array of strings.
thanks.

What ConvertAll() does is change the type of the reference. So you have a StringBuilder reference, and you copy that reference to a variable of type object:
var builder = new StringBuilder();
builder.AppendLine("Hello, World!");
object converted = (object)builder;
Now converted holds an object reference, but the actual object it's pointing to still is the StringBuilder that you instantiated.
The same is happening in the delegate you create. You can't just cast something to a base class and "cut off" all parts that aren't in the base class.
If you have a scenario where you think you need this, create a custom conversion.

Related

Changing one property in multidimensional array changes other array's properties too

I have a multidimensional array called SensorGetResult. In some cases this array can have a single array in it. If that happens, I must copy this one array and add it again, so I must have 2 arrays now. Then I need to change these array's dateTime property. This is my code:
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
sensorGet.SensorGetResult[0].dateTime = end; //It works correctly including this line
sensorGet.SensorGetResult[1].dateTime = start; //At this line both array's dateTime property changes
Why can't I assign dateTime properties to each array individually?
It looks like you are using a reference type for your helperArray.
When the following code executes:
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
What actually happens is you take a the first element of SensorGetResult which is a reference to the object (which I believe you intend to copy) and append the reference to the list thus resulting in a list which has two references to the same object in the memory.
If you want it to make a copy of the object, you have to implement that by yourself. Usually this means creating a new object of the same type and copying all the properties.
var objectToCopy = sensorGet.SensorGetResult[0];
var helperArray = new WhatEverTypeIsYourHelperArray {
Property1 = objectToCopy.Property1,
Property2 = objectToCopy.Property2,
// etc.
};
sensorGet.SensorGetResult.Add(helperArray);
But you have to be aware if any of the properties is furthermore a reference type, you need to do this recursively for all the properties.
If WhatEverTypeIsYourHelperArray is type you own, you could utilize Object.MemberwiseClone method and make it all easier for yourself. You can do this by implementing a method like the following. As a note, MemberwiseClone is a protected method hence the need of a new method in your class.
public WhatEverTypeIsYourHelperArray Clone() {
return (WhatEverTypeIsYourHelperArray)this.MemberWiseClone();
}
But even the MemberwiseClone() method doesn't copy reference types for you, rather just copies the pointers to the objects which means that all the properties of reference type of both the original and the cloned object will point to the same objects in the memory.
SensorGetResult row seems to be a reference type.
So when you wrote
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
you actually said that new row in SensorGetResult will point to the same object as the first one.
You can implement method like below:
public SensorGetResultRow Clone()
{
return new SensorGetResultRow (this.field1, this.field2, etc...)
//or if you use parameterless constructor
return new SensorGetResultRow ()
{
field1 = this.field1
//etc.
}
}
and use it:
var helperArray = sensorGet.SensorGetResult[0].Clone();

Enumerable.Repeat for reference type objects initialization

I have a question about Enumerable.Repeat function.
If I will have a class:
class A
{
//code
}
And I will create an array, of that type objects:
A [] arr = new A[50];
And next, I will want to initialize those objects, calling Enumerable.Repeat:
arr = Enumerable.Repeat(new A(), 50);
Will those objects have the same address in memory?
If I will want to check their hash code, for example in that way:
bool theSameHashCode = questions[0].GetHashCode() == questions[1].GetHashCode();
This will return me true, and if I will change one object properties, all other objects will change it too.
So my question is: is that properly way, to initialize reference type objects? If not, then what is a better way?
Using Enumerable.Repeat this way will initialize only one object and return that object every time when you iterate over the result.
Will those objects have the same address in memory?
There is only one object.
To achieve what you want, you can do this:
Enumerable.Range(1, 50).Select(i => new A()).ToArray();
This will return an array of 50 distinct objects of type A.
By the way, the fact that GetHashCode() returns the same value does not imply that the objects are referentially equal (or simply equal, for that matter). Two non-equal objects can have the same hash code.
Just to help clarify for Camilo, here's some test code that shows the issue at hand:
void Main()
{
var foos = Enumerable.Repeat(new Foo(), 2).ToArray();
foos[0].Name = "Jack";
foos[1].Name = "Jill";
Console.WriteLine(foos[0].Name);
}
public class Foo
{
public string Name;
}
This prints "Jill". Thus it shows that Enumerable.Repeat is only creating one instance of the Foo class.
When using the following code to create an array:
var foos = Enumerable.Repeat(new Foo(), 2).ToArray();
The reason why each location in the array is the same is because you are passing an object, and not a function that creates an object, the code above is the same as:
var foo = new Foo();
var foos = Enumerable.Repeat(foo , 2).ToArray();
The reason above also explains why using a Select statement, like in the code below, creates a new object for each entry, because you are passing a function that dictates how each object is created, rather than the object itself.
Enumerable.Range(1, 2).Select(i => new Foo()).ToArray();
I would use a simple for loop to populate an array with new reference types.

Method has array param, passing array objects to parameter

I have a constructor that has a similar signature to ExampleObject(string name, params object[]).
My usual procedure of passing items to this constructor is:
var thisObject = new ExampleObject("name", obj1, obj2, obj3);
Is there anyway I can initialize a separate array of objects, and pass that array to the constructor IN Addition to how I normally do it, by means of LINQ or some other magic?
Ideal result:
object[] specialObjects = {new object("specObj1"), new object("specObject2")}
var thisObject = new ExampleObject("name", obj1, obj2, specialObjects...
Would I need to use LINQ's Enumerable, ForEach, or something I'm completely unaware of, or is something like this not feasible and I should include obj1 and obj2 into specialObjects?
The params keyword is just syntactic sugar for the creation of an array - you could as well do it with an array literal, i.e.
var thisObject = new ExampleObject("name", new [] {obj1, obj2, obj3});
Once you look at it this way, you realize that it is not possible to use an array for part of the parameter list. You have to create a new array. You could definitely use LINQ. Here is an example:
var thisObject = new ExampleObject("name",
(new [] {obj1, obj2}).Concat(specialObjects).ToArray());
(Note that there is a performance penalty involved in using code like this as several temporary objects are created. If you are concerned about performance it may be a better idea to create a specialized overload that takes the array and extra parameters).

Access object property in array

class Program{
static void Main(string[] args){
object[] array = new object[1];
CreateItem item = new CreateItem();
item.name = "Necklace";
item.value = 5;
array[0] = item;
Console.WriteLine(array[0].name); //This part of the code doesn't work.
//It can't find the property name.
Console.ReadLine();
}
}
public class CreateItem {
public string name;
public int value;
}
Hi there! First of all I'd like to say that I'm not very familiar with objects, so excuse any mistakes you can see in the code (Although feel free to correct them, it'd be a great way to learn).
I've been working on making a small game using C#, but I came across a problem: I can't access my object properties when I put them in an array. Does anyone know which code I should use to be able to access my object properties while they're in an array?
Thanks for reading, and once again, excuse any silly mistakes I made, I'm fairly new to working with objects.
You shouldn't use an object array when you have a strong type that you're interested in using (and you know the type already).
CreateItem[] array = new CreateItem[1];
CreateItem item = new CreateItem();
item.name = "Necklace";
item.value = 5;
array[0] = item;
Console.WriteLine(array[0].name);
Necklace will now be outputted as expected.
You should probably look at using Generics and Lists, it is a very common and a valuable concept to grasp, as is the concept of Boxing and Unboxing which Generics solves.
class Program{
static void Main(string[] args){
List<CreateItem> list = new List<CreateItem>();
CreateItem item = new CreateItem();
item.name = "Necklace";
item.value = 5;
list.Add( item );
Console.WriteLine(list[0].name); //This part of the code doesn't work.
//It can't find the property name.
Console.ReadLine();
}
}
You could cast the object to your type, i.e.:
Console.WriteLine(((CreateItem)array[0]).name);
or (more effectively)
define your array as CreateItem[] array = new CreateItem[1];
Line
object[] array = new object[1];
creates an array of elements of type Object which is the base class for all other classes in .NET.
When you do:
array[n] = item;
an implicit conversion to the base type occurs and through array[n] you can access only members of the Object type portion of the CreateItem object (like ToString() or GetType() - their overrides will be called).
If you want to access entire CreateItem object, you have to cast the reference to the base type back to the original type, by using cast operator for example:
var name = ((CreateItem)array[0]).name;
This explicit casting is error-prone, has a run-time overhead and it is a sign of the poor design. When you know the type of the collection in advance, declare the collection of that type as other answers are suggesting:
// you can use array if you know number of items in advance and that number of elements will not change
CreateItem[] array = new CreateItem[N];
// use list if number of elements might change
List<CreateItem> list = new List<CreateItem>();

Is there a way to specify an anonymous empty enumerable type?

I'm returning a Json'ed annonymous type:
IList<MyClass> listOfStuff = GetListOfStuff();
return Json(
new {
stuff = listOfStuff
}
);
In certain cases, I know that listOfStuff will be empty. So I don't want the overhead of calling GetListOfStuff() (which makes a database call).
So in this case I'm writing:
return Json(
new {
stuff = new List<ListOfStuff>()
}
);
which seems a bit unnecessarily verbose. I don't care what type of List it is, because it's empty anyway.
Is there a shorthand that can be used to signify empty enumerable/list/array? Something like:
return Json(
new {
stuff = new []
}
);
Or have I been programming JavaScript too long? :)
Essentially you want to emit an empty array. C# can infer the array type from the arguments, but for empty arrays, you still have to specify type. I guess your original way of doing it is good enough. Or you could do this:
return Json(
new {
stuff = new ListOfStuff[]{}
}
);
The type of the array does not really matter as any empty enumerable will translate into [] in JSON. I guess, for readability sake, do specify the type of the empty array. This way when others read your code, it's more obvious what that member is supposed to be.
You could use Enumerable.Empty to be a little more explicit:
return Json(
new {
stuff = Enumerable.Empty<ListOfStuff>()
}
);
Although it isn't shorter and doesn't get rid of the type argument.
dynamic is also a better option when dealing with an anonymous type
Enumerable.Empty<dynamic>()
this worked well for me
You might not care what type of list it is, but it matters to the caller. C# does not generally try to infer types based on the variable to which it is being stored (just as you can't create overloads of methods on return type), so it's necessary to specify the type. That said, you can use new ListOfStuff[0] if you want an empty array returned. This has the effect of being immutable (in length) to the caller (they'll get an exception if they try to call the length-mutating IList<T> methods.)
Yes, there is. You have to define an array with as least one element, and use linq to filter the array leaving no elements. Example:
var foo = new
{
Code = 1,
Name = "Bar",
Value = (float?)5.0
};
//use an empty object (or any object) to define the type of the array
var emptyArrayOfFooType = new[] {
new
{
Code = (int)0,
Name = (string)null,
Value = (float?)null
}
}.Where(e => false).ToArray(); //use linq to filter the array leaving no elements
//you can use an existing anonymous type variable too
var anotherEmptyArray = new[] { foo }.Where(e => false).ToArray();
//this array with one element has the same type of the previous two arrays
var fooArray = new[] { foo };
//all arrays have the same type, so you can combine them
var combinedArrays = emptyArrayOfFooType.Concat(anotherEmptyArray).Union(fooArray);
send a generic type?:
List<Object>()
or send an empty object array: new Object[0]
I guess you are talking about C# here. My knowledge is limited in C# but I don't think you can create a new object with no type. Why can't you return a generic new List[] ? (might be mixing Java generics here, am not sure is one can return a generic type list in C#).

Categories