How to declare an array of deserialized class parameters without initializing it? - c#

I consider this as a continuation of what I've learned from my two previous threads. Instead of Javascript I will be using pure C#.
I have a class with 3 parameters in it, and I am creating a variable which is a result of deserialization to class type
var param = js.Deserialize<ClassName>(jqData.Params);
Based on what I've learned from my first thread, it stores values based on inputs I've made within 3 textboxes that I have.
For our purposes, let's assume I only placed input in a second textbox out of three, so the values would be null, "abc", null.
Now, I got some very good suggestions from my second post, which I want to implement.
I want to create an array of objects, WITHOUT initializing, since those objects already hold values, reduce array down to 1 element based on criteria from that excellent post, and then proceed with my validation logic.
However, I am struggling with declaring array part. From what I saw here in SO, most of threads are talking about declaring and initializing those elements. I don't need it.
What I need is to declare an array, which would have class elements in it, something like array = [param.elem1, param.elem2, param.elem3], and when I run a code, it will return [null, "abc", null].
Can you please point me in the right direction on how to properly declare such array?

Your idea was close to how this can be handled. Just change your array = [param.elem1, param.elem2, param.elem3] to:
var myArray = new object[] { param.elem1, param.elem2, param.elem3 };
If you know the type of param.elem1/2/3, you can use the specific type (e.g. string[] instead of object[]).

Related

C# : Changing copy of array changes array itself

I have a very basic question in C#. So I have an array of int called m_permutation (property of a class), and in a method of the class I have the following code:
int[] newPermutation = new int[m_permutation.Length];
newPermutation = m_permutation;
newPermutation[0] = 5;
I am confused as to why m_permutation is also changed in this code, and how can I fix it ?
I understand that I can initialize newPermutation via a loop for, to get the same values of m_permutation, and that fixes it. However, can somebody explain why this happens, and what is the best fix ?
Thank you,
Bogdan
There's some good, and some bad, about your expectations for your code.
Let's go through what your code is actually doing:
int[] newPermutation = new int[m_permutation.Length];
This will declare a new variable, newPermutation, to be an array of ints, and then construct a new int array containing m_permutation.Length elements.
So far so good.
The next line, not so much:
newPermutation = m_permutation;
This line will actually replace the reference in your array variable newPermutation to, after the assignment, refer to the same array as m_permutation.
Let's consider what an array variable actually is.
When you do this:
int[] x = new int[5];
Then you're doing a couple of things:
You're declaring a variable, x
You're constructing a new object containing the int array
You're assigning the variable, x to refer to this object
After the 2nd line:
newPermutation = m_permutation;
you're essentially saying this:
OK, you know that array we just constructed? Forget that
Let's now refer to this other array, the one that the variable m_permutation is also referring to.
So when this line executes:
newPermutation[0] = 5;
You're essentially saying: The array that newPermutation is now referring to, its first element should now have the value 5.
Since newPermutation at this point refers to the same array as m_permutation, it appears that you're modifying an additional array but in reality you only have one array. You do, however, have two variables referring to the same array.
I recommend you read my answer here regarding pointers since this is relevant.
However, there is an easy fix to your problem.
You can ask for a copy of the array, instead of a reference to the original one.
Simply change your code to this:
int[] newPermutation = m_permutation.ToArray();
The .ToArray() method is guaranteed to return a new array, so this won't be shared with the original.
Bear in mind, however, that if you do this with anything more complex than an int, such as an object, you're only getting copies of the object references, not the objects themselves. You can get back to Stack Overflow with new questions when/if you get to this point.
Because they both reference the same object in memory.
You can use,
Array.Copy(m_permutation, newPermutation,m_permutation.Length );

Can you make an element and an element-in-a-list act like the same object?

I know from questions like: "Is it Possible to store references to objects in list?" that you can modify a property on an object without removing the object from a list. So you can make a wrapper class and put your object inside it, then modify the value. However, if what you are trying to do is change the object itself...
What I want to know is: Can you make a series of objects, store them in a list like structure, and then access them from either the list or the objects? Can you make object and the object-in-the-list act like they are the same object? Can you do this if you use an array?
Using System;
Using System.Collections.Generic;
Namespace Project1
{
Class Test
{
Public static void Main()
{
int one = 1;
int two = 2;
int num = 3;
List<int> myList = new List<int>();
myList.Add(one);
myList.Add(two);
myList.Add(num);
myList[2] = 4; // I want this to also set num to 4
num = 5; // I want this to also set myList[2] to 5
Console.WriteLine(myList[2]); //prints 4
Console.WriteLine(num); //prints 5
}
}
}
Looking at your code example, I think I understand what you are getting at. Basically, you want to access the element in the array directly and not by the indexed property accessor. It's very simple to do that, as long as the item in the array is a reference type. However, this won't work with value types, because the standalone variable and the indexed property are pointing to different memory storage spaces when value types are involved.
To illustrate:
listOfPersons[2] = new Person { Name = "Homer Simpson", Age = 35 };
Console.WriteLine(listOfPersons[2].Name); // will show Homer Simpson
Person myself = listOfPersons[2];
myself.Name = "Bart Simpson";
Console.WriteLine(myself.Name); // will show Bart Simpson
Console.WriteLine(listOfPersons[2].Name); // will show Bart Simpson
Console.WriteLine(listOfPersons[2].ReferenceEquals(myself)); // will show true
On the other hand:
listOfInts[2] = 2;
Console.WriteLine(listOfInts[2]); // will show 2
int myInt = listOfInts[2];
myInt = 5;
Console.WriteLine(myInt); // will show 5
Console.WriteLine(listOfInts[2]); // will show 2...
Hope this helps!
First, your code doesn't have any objects except the List object you created. Integers are not objects. You could box the integers, but C# will copy on both boxing and unboxing so you couldn't use that for what you are asking.
In general, to get the behavior you're looking for, you need to use a reference type (i.e. an object) that exposes a property of the type you want to use. Note, however, even for reference types, you can absolutely have two references that refer to the same object, but the references themselves are distinct - so changing one reference to refer to a different object won't change what the other reference is referring to.
You can pass parameters by reference to a method or function call, but you can't store this reference (not even by trying to close over it with a lambda), so you can't keep a reference in a list and use it to update the variable that was added to the list.
You could mock up a very cludgy workaround where you maintained a list of Func<T>/Action<T> getter/setter pairs and use lambdas to close over the original variable before you add it to the collection, but if you're going to that level, you are long past the point where you should take a step back and figure out why you're taking the path of most resistance.
Simply put, this isn't the kind of thing you really should find yourself needing to do - and if it's something you encounter, it might be a sign you've missed another, better way to architect your code.

Is the best way to reference these object properties?

Just wondering if this is the most eloquent way to write this code:
var myObj = new Class();
int myId1 = myObj.Id1;
int myId2 = myObj.Id2;
Was trying to do it in 2 lines like:
int myId1 = new Class().Id1;
int myId2 = new Class().Id2;
But I suspect this is more inefficient as instantiating 2 objects instead of 1.
So what is the leanest way to write the above code.
Thanks.
EDIT.
I am trying to write a central bit of code, and chose to write it in a class. I am trying to insulate the application from the details as to how this values are acquired. From a comment below, it would seem that the use of a static class would be most eloquent.
EDIT2:
After thinking about this a little more, I think it is best if I do use a non static approach since I can populate the class properties in the constructor. So therefore I need one "new" and 2 accessor lines of code, so approach 1 seems best.
If you only want to assign myId1 to the default value of Class().Id1, and the same with 2, then you can do it your second way.
However, if you want to be assigning those two variables to the values of a manipulated Class object, then do it the first way.
Instantiating a whole new object just to get a second default value is wasteful.

Removing from list recursively in C#

I have the following recursive function that is used to search down a hierarchical tree and remove found objects from a list:
private List<Tag> RemoveInvalidTags(Device device, List<Tag> tags)
{
var childDevices = device.ChildDevices.Select(c => c.ChildDevice);
foreach (var child in childDevices)
{
tags.Remove(child.Tag);
RemoveInvalidTags(child, tags);
}
return tags;
}
What I am expecting this to do is remove all child device tags at this level from the tags list, call the function recursively for your children, then return that list up to the previous level.
Will this pass the tags list by reference and modify the original passed list? Or should I be doing something along the lines of
validTags = CollectValidTags(child, tags);
and adding up all the returned lists?
Will this pass the tags list by reference
No. The list object is passed "by value" (but see next). (ref or out is required to "pass by reference" in C#, but that is not being done here, nor does it need to be.)
and modify the original passed list?
Yes. This is because the list object is passed. And that list object is mutated. Passing a reference type (anything defined with class) never implicitly makes a copy/clone/duplicate. An object is what it is.
Now, back to "pass by value": the "value passed" is the value of the "reference" (internal, no need to concern with this): this calling strategy is better known as Call/Pass By Object Sharing in a langauge like C#. The same object is shared (just as if it were assigned to two different variables). (Value types -- a struct -- are different in that they (often) are copied/duplicated on the stack, but a List<T> is a class.)
Or should I be doing something along the lines of
It depends upon the desired semantics. Is the caller expecting the side-effects directly or indirectly? Can the mutation side-effect lead to unexpected scenarios? Make sure to document it either way. (I prefer the way that guarantees the initial object is not mutated.)
Hope that clears some things up.
Happy coding.
In your code you are modifying the items in your tags parameter and passing back the modified list as your result. You want to avoid modifying lists in this way - especially inside loops where it can cause you grief in many situations.
I have a LINQ-based alternative for you.
If I understand the intent of your code you want to do something like this:
Func<Device, IEnumerable<Device>> flatten = null;
flatten = d =>
{
return (new [] { d }).Concat(
from c in d.ChildDevices
from f in flatten(c)
select f);
};
var collectedValidTags = flatten(device).Select(d => d.Tag);
var result = tags.Except(collectedValidTags).ToList();
This approach doesn't pass your list of tags around so there is no chance of modifying your original list.
Does this help?
Short answer - your code will do what you want.
Long answer - you should read descriptions of what the ref keyword does. I would suggest you read as many descriptions as possible; there are many different ways to articulate it ("I like to think of it as... ") and some will work for you whilst others won't. If you read many descriptions (from people who understand it) then some kind of understanding should gel for you.
Here's a list to get you started:
Use of 'ref' keyword in C# (my answer)
C# ref keyword usage
Passing by ref?
Example of practical of "ref" use

Does Array.ToArray<>() return the original array if it is the same type?

I deal with a framework on a daily basis where we sometimes provide methods that accept IEnumerable<MyBusinessObject> as a parameter in order to show user interfaces, perform calculations etc.
If I pass in an array of MyBusinessObject like so:
MyBusinessObject[] myArray = new MyBusinessObject { obj1, obj2, ..., objN };
frameworkClass.MyMethod(myArray);
....
public class FrameworkClass
{
public void MyMethod(IEnumerable<MyBusinessObject> objs)
{
// Other code that uses the enumerable
MyBusinessObject[] objectArray = objs.ToArray();
// More code that uses the enumerable
}
}
Does the line objs.ToArray() simply resolve the IEnumerable<MyBusinessObject> back to the original array, or does it copy it to a whole new array, ready for use?
No, you will always get a new copy of the array, though the objects in it aren't copies, they are the same references as in the original array.
It would be very inconsistent for changes to the returned array to sometimes affect the source and sometimes not. ToList works the same way for the same reason.
You can check source code (as of 2015) if you need to review details: Enumerable.ToArray which in turn creates copy of elements (optimized for ICollection and hence Array[], but still making copy) with internal Buffer class.
You will get a new copy of the array if there is one or more element in it. For empty arrays, you might get the same array back, at least in .NET 5:
Console.WriteLine(Object.ReferenceEquals(Array.Empty<string>(), Array.Empty<string>().ToArray()));
This returns true.

Categories