Modifying LinkedListNode property in C# - c#

I'm working with LinkedList in C#.
All I want to do is a simple code that excludes B from the list and directly connect node A with B.Next:
A.Next = B.Next;
B.Next.Previous = A;
But got an error:
Property or indexer System.Collections.Generic.LinkedListNode<>.Next
cannot be assigned to it is read only.
Is it possible to somehow get the right to assign values to Next and Previos properties?
Or how can I avoid this error?
Best regards.

You can just call LinkedList<T>.Remove and pass in B. The Remove method takes care of this for you.

Related

Why can't I change value without first assigning a variable?

Hi I stumbled upon something strange, I wanted to stop the emission of particle system as follows:
laser.GetComponent<ParticleSystem>().emission.enabled = false;
But I get error CS1612 (cannot modify the return value cause it is not a variable)
But
var emissionModule = laser.GetComponent<ParticleSystem>().emission;
emissionModule.enabled = false;
Works, now I searched about this issue but everyone says you can't do it because the return value is returned by value and not by reference, but this can't be true because the code above does indeed change the emission module to false in game, it didn't change a local copy in my code it actually changed it on the reference, so my question is why creating a variable first does anything different then just changing it on the same line? it would have worked in JS/Python
If I had to do something like
var emissionModule = laser.GetComponent<ParticleSystem>().emission;
emissionModule.enabled = false;
laser.GetComponent<ParticleSystem>().emission = emissionModule
I would have understand this issue better, but I don't need to do it like here, I don't need to assign it back again somewhy, it works fine as I showed in the 2nd example so it doesn't make sense, emissionModule seems to be a reference and not a value copy
TL;DR version:
Here is a full example of the code:
void changeLasers(bool isActive) {
foreach (GameObject laser in lasers) {
var emissionModule = laser.GetComponent<ParticleSystem>().emission;
emissionModule.enabled = isActive;
}
}
Which is weird, it works but I didn't need to assign it back again so why couldn't I do it in 1 line? seems weird that c# forces me to use another variable here.
This gives the CS1612 error:
void changeLasers(bool isActive) {
foreach (GameObject laser in lasers) {
laser.GetComponent<ParticleSystem>().emission.enabled = isActive;
}
}
emissionModule seems to be a reference and not a value copy
Well, it is not ;)
EmissionModule is a struct and therefore the ParticleSystem.emission property returns a copy by value!
Since Unity is actually mainly a C++ engine and the c# is just a layer on top of it most of the components properties are actually just wrappers for getters and setters into the underlying C++ part where they are actually implemented. (See source code)
=> Most of the properties in Unity behave exactly like that and you always need to use the getter, store them, modify them and assign them back again.
In this case it is very possible that internally that struct still aslso holds a reference to the system which allows the enabled property to directly affect the underlying system.
Still since c# is how it is you can not directly modify the value of the returned struct.
derHugo's answers the c# issue here (we indeed get a struct by value),
I want to chime in about why we don't need to re-assign the structure back:
It wouldn't have worked normally, this is black magic done by the Unity engine behind the scenes (basically applies your struct changes without you needing to re-assign the struct back).
More on this subject here:
https://forum.unity.com/threads/is-particlesystem-emissionmodule-a-struct-and-how-should-we-use-it.821988/
And a bit more detailed:
https://blog.unity.com/technology/particle-system-modules-faq

Unity particleSystem main access cannot modify struct member when accessed struct is not classified as a variable

I have the following code to modify a property of the ParticleSystem in Unity
waterCone.main.loop = true;
However, this is giving me the following error
Property 'main' access returns temporary value. Cannot modify struct member when accessed struct is not classified as a variable
Unity's own docs seem to show this code being used as follows
var waterConeMain = waterCone.main;
waterConeMain.loop = true;
With no errors at all.
Why does this fix the problem, as far as my understanding of c# goes, this should be the exact same.
In fact, as far as I can tell neither should work.
I tried to compare the two in Sharplab but the first would not even compile.
What's going on here? And why is this variable necessary?
(edit)
From looking into the source code, it looks like ParticleSystem.main is doing this
MainModule main => new MainModule(this);
And Main is a struct, which has loop as a property like
get => ParticleSystem.MainModule.get_loop_Injected(ref this);
set => ParticleSystem.MainModule.set_loop_Injected(ref this, value);
But really this seems to leave me with more questions than answers, why is this a compilation error when I don't use a temporary variable?
The return type of ParticleSystem.main is a struct type, you cannot directly modify its value. The main reason why you can't do this is that the returned struct value is just a copy, so it's usually meaningless to modify the value at this time and it will cause some imperceptible errors. Quote the explanation from official document
This error occurs because value types are copied on assignment. When you retrieve a value type from a property or indexer, you are getting a copy of the object, not a reference to the object itself. The copy that is returned is not stored by the property or indexer because they are actually methods, not storage locations (variables). You must store the copy into a variable that you declare before you can modify it.

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

Finding an item by object value in Combobox

I have a combo box that is populated with an Arraylist, like below. If I have another instance of same object, how do I select that object in the combobox? Please look at the code below to understand.
MakeEntity selectedMake = Make.GetMakeByTitle("Honda");
List<MakeEntity> allMakes = Make.GetAllMakes();
cbVehicleMake.DataSource = allMakes;
cbVehicleMake.SelectedIndex = cbVehicleMake.Items.IndexOf(selectedMake);
But last line is not working as expected. Can I get it to run at all or am I going in the wrong direction? Should MakeEntity implement iComparable?
Assuming MakeEntity has an property called id!
cbVehicleMake.SeletedItem=allMakes.Find(q=>q.Id==selectedMake.Id))
You shouldn't need to implement IComparable for IndexOf, just Equals. Otherwise it will default to Object.Equals, which only matches if the two references are to the same instance. (Not sure if this is a problem or not without seeing the definition of MakeEntity.)
Also, just use:
cbVehicleMake.SelectedItem = selectedMake;
This will internally handle finding the object in the options.
Documentation: http://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.selecteditem.aspx

Replace object but keep previous memory location in c#

Let's say I have a list:
List<object> list = new List();
list.Add(object1);
list.Add(object2);
object foo = list[0];
How do I make a call to list to replace list[0] such that foo will automatically point to the newly replaced object?
I know this line won't do the trick as foo will continue pointing to the old value of list[0]...
list[0] = object3;
Thanks!
It's not possible in my opinion. You need an additonal level of indirection which you have to implement yourself.
You could use a delegate/ anonymous lambda that fetches list[0]:
Func<object> foo = () => list[0];
Of course that changes the syntax slightly since it's now foo() instead of foo but it has the effect that you can fetch the value of list[0] at any time later and it always gets the current value.
What you really want to be able to do is to override the assignment operator but that's not possible in C#. The closest you'll get is to create a class that behaves a bit like Nullable<T> having a .Value property on it and assign to that .Value property instead of overwriting the object itself in the list.
You can use the fixed keyword but only in unsafe code. But i'm not sure what your attempting to do so it may not suite your needs if you need this level of control c++ cli would be a better choice.
Unsafe pointers are one possibility: http://msdn.microsoft.com/en-us/library/y31yhkeb(v=vs.80).aspx
For "safe" code, you can do something like store your value in an array of length 1, and then only store references to the array and always access the value by array[0], but this is a bit of a hack and there is probably a better way to do what you want to accomplish.

Categories