How to set a specific member of a struct, using indexing in C# - c#

Assuming I have a struct:
struct Vector
{
public int X, Y;
// ...
// some other stuff
}
and a class:
class Map
{
public Vector this[int i]
{
get
{
return elements[i];
}
set
{
elements[i] = value;
}
}
private Vector[] elements
// ...
// some other stuff
}
I want to be able to do something like: map[index].X = 0; but I can't, because the return value is not a variable.
How do I do this, if at all possible?

You should avoid mutable structs.
If you want your type to be mutable use a class instead.
class Vector
{
public int X { get; set; } // Use public properties instead of public fields!
public int Y { get; set; }
// ...
// some other stuff
}
If you want to use a struct, make it immutable:
struct Vector
{
private readonly int x; // Immutable types should have readonly fields.
private readonly int y;
public int X { get { return x; }} // No setter.
public int Y { get { return y; }}
// ...
// some other stuff
}

The compiler prevents you from doing this because the indexer returns a copy of an object not a reference (struct is passed by value). The indexer returns a copy, you modify this copy and you simply don't see any result. The compiler helps you avoid this situation.
If you want to handle such situation you should use class instead or change the way you deal with Vector. You shouldn't modify it's value but initialize it's values in constructor, more on this topic: Why are mutable structs “evil”?.

define Vector as class,
or
store value in a temporary variable
var v = map[index];
v.X = 0;
map[index] = v;
or
add function to change
map[index] = map[index].Offset()
or
let the [] operator return a setter class
class Setter { Vector[] Data; int Index; public double X { get { return Data[Index]; } set { Data[Index] = new Vector(value, Data[Index].Y); }}}
public Setter this[int i]
{
get
{
return new Setter() { Data = elements, Index= i };
}
}

Although generic classes work pretty well for many purposes, they do not provide any reasonable way to access structs by reference. This is unfortunate since in many cases a collection of structs would offer better performance (both reduced memory footprint and improved cache locality) and clearer semantics than a collection of class objects. When using arrays of structs, one can use a statement like ArrayOfRectangle[5].Width += 3; with very clear effect: it will update field X of ArrayOfRectangle[5] but it will not affect field X of any other storage location of type Rectangle. The only things one needs to know to be certain of that are that ArrayOfRectangle is a Rectangle[], and Rectangle is a struct with a public int field X. If Rectangle were a class, and the instance held in ArrayOfRectangle[5] had ever been exposed to the outside world, could be difficult or impossible to determine whether the instance referred to by ArrayOfRectangle[5] was also held by some other code which was expecting that field X of its instance wouldn't change. Such problems are avoided when using structures.
Given the way .net's collections are implemented, the best one can do is usually to make a copy of a struct, modify it, and store it back. Doing that is somewhat icky, but for structs that aren't too big, the improved memory footprint and cache locality achieved by using value types may outweigh the extra code to explicitly copy objects from and to the data structures. It will almost certainly be a major win compared with using immutable class types.
Incidentally, what I'd like to see would be for collections to expose methods like:
OperateOnElement<paramType>(int index, ref T element, ref paramType param, ActionByRef<T,paramType> proc) which would call proc with the appropriate element of the collection along with the passed-in parameter. Such routines could in many cases be called without having to create closures; if such a pattern were standardized, compilers could even use it to auto-generate field-update code nicely.

Related

How can I make a constant static immutable instance of a class?

I have a simple class that represents 3 dimensional coordinates called Coord3 that simply has x, y, and z int values.
I want to declare a static constant variable Coord3.zero where x, y, and z are set to 0.
I have attempted this with:
public static readonly Coord3 zero = new Coord3(0, 0, 0);
However I found that this variable can be changed. For example if I do
Coord3 coord = Coord3.zero;
coord.x = 5;
this actually changes the x value of Coord3.zero to be 5. Maybe I am misunderstanding readonly? I know that in Unity there is Vector3.zero which never changes. I am trying to achieve the same effect.
Maybe I am misunderstanding readonly?
Yeah, readonly means you can't change the reference of your variable. In other words, you can't write Coord3.zero = new(...);
Now, the way these things are usually written is as structs, where fields are by default immutable. That would solve your problem right there. That is also how it's done in Unity. Note that you can also do this with classes, by having only getters on your properties and filling them in once from your constructor, but classes are very heavy weight for these small types.
readonly is not quite the same thing as immutable in the sense you mean. readonly means you cannot assign to a variable. So you couldn't do
public static readonly Cord3 zero = new Cord3(0, 0, 0);
zero = new Cord3(0, 0, 1);
In order to achieve the effect you want, you could need to create a class, struct or record with readonly properties or fields. There's no way to achieve that effect with a type defined in an internal library. If the type allows mutability on a field or property, that field or property is mutable.
Marking zero as readonly indeed prevents you from changing what zero stores. You cannot reassign it.
zero = new Coord3(1, 1, 1); // error
Note that since Coord3 is a class, zero.x = 5; isn't actually changing what zero stores. You are just changing some property of the object that zero is referring to. zero is still storing the same reference to the same old object.
You could prevent this by not providing any public API in Coord3 that would change its fields' values - for example, by making x, y, z all read-only properties:
public int X { get; }
public int Y { get; }
public int Z { get; }
Of course, this wouldn't work if you just want to prevent setting the properties on zero, but allow the modification of Coord3 on other objects.
I would suggest that you make Coord3 a struct:
public struct Coord3 {
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
Now zero stores the fields' values directly, rather than a reference to an object. zero.x = 5; would produce an error, because you are modifying what zero directly stores.
Note that Unity's Vector3 for example, is also a struct.
I think you can make an immutable base class and your Coord3 inheriting this class.
public class BaseCoord3
{
// protected means it can only be used by BaseCoord3 and Coord3
protected int x;
// equivalent to public int X { get { return x; } }
public int X => x;
}
public class Coord3 : BaseCoord3
{
public override int X
{
get { return x; }
set { x = value; }
}
public static BaseCoord3 Zero => new BaseCoord3(0,0,0);
}
This should work similar to the way with Readonly versions of collections in c#. I think the struct solutions are the way to go though.
How about you just use a get-property to never change the zero object?
public class Coord3
{
public static Coord3 Zero => new Coord3(0,0,0);
}
Then you won't be able to change the values of Zero, but you will maintain the functionality of Coord3 objects.
Coord3 a = Coord3.Zero;
a.x = 2; // changes a.x, but not Coord3.Zero.x

How to make struct immutable inside a class definition

I have a question about creating an immutable struct inside a class definition. I want to define the struct outside the class but use that same struct type in the class definition while maintaining immutability. Will the code below achieve this?
namespace space
{
class Class1
{
public Struct {get; set;}
}
public Struct
{
public Struct(string strVar)
{
StructVar = strVar;
}
public string StructVar {get;}
}
}
Also, if I have a struct within a struct like:
class Class1
{
public Struct2 {get; set;}
}
public struct Struct2
{
public Struct2(string str, InStruct inStrct)
{
StrVar = str;
InStruct = inStrct;
}
public string StrVar {get;}
public InStruct InStruct {get;}
}
public struct InStruct
{
public InStruct(Array ary)
{
StrArray = ary
}
public Array StrArray {get;}
}
Does this also maintain immutability?
Lastly, if the size of the array in the InStruct is likely to be quite long, should I not use a struct at all and just put the array itself into the class definition instead? Am I just going struct crazy?
My concern is that because I'm doing a {set;} in the class definition that I'm breaking a rule somewhere. I would put the struct in the class definition itself but I didn't like to have to continuously call class constructors over and over to create each struct, that kind of seemed to defeat the purpose of using a struct in the first place.
It's a little difficult to give a complete answer without understanding exactly what you are trying to accomplish, but I'll start with a few important distinctions.
First, in C#, the struct/class distinction isn't about mutability per se. You can have a immutable class, like this one
public class CannotBeMutated
{
private string someVal;
public CannotBeMutated(string someVal)
{
_someVal = someVal
}
public string SomeVal => _someVal;
}
and a mutable struct, like this one
// This is not at all idiomatic C#, please don't use this as an example
public struct MutableStruct
{
private string _someVal;
public MutableStruct(string someVal)
{
_someVal = someVal;
}
public void GetVal()
{
return _someVal
}
public void Mutate(string newVal)
{
_someVal = newVal;
}
}
Using the above struct I can do this
var foo = new MutableStruct("Hello");
foo.mutate("GoodBye");
var bar = foo.GetVal(); // bar == "GoodBye"!
The difference between structs and classes is in variable passing semantics. When an object of a value type (e.g. a struct) is assigned to a variable, passed as a parameter to or returned from a method (including a property getter or setter) a copy of the object is made before it is passed to the new function context. When a object of a reference type is passed as a parameter to or returned from a method, no copy is made, because we only pass a reference to the object's location in memory, rather than a copy of the object.
An additional point on struct 'copying'. Imagine you have a struct with a field that is a reference type, like this
public struct StructWithAReferenceType
{
public List<string> IAmAReferenceType {get; set;}
}
When you pass an instance of this struct into a method, a copy of the reference to the List will be copied, but the underlying data will not. So if you do
public void MessWithYourSruct(StructWithAReferenceType t)
{
t.IAmAReferenceType.Add("HAHA");
}
var s = new StructWithAReferenceType { IAmAReferenceType = new List()};
MessWithYourSruct(s);
s.IAmAReferenceType.Count; // 1!
// or even more unsettling
var s = new StructWithAReferenceType { IAmAReferenceType = new List()};
var t = s; // makes a COPY of s
s.IAmAReferenceType.Add("hi");
t.IAmAReferenceType.Count; // 1!
Even when a struct is copied, its reference type fields still refer to the same objects in memory.
The immutable/mutable and struct/class differences are somewhat similar, insofar as they are both about where and whether you can change the contents of an object in your program, but they are still very distinct.
Now on to your question. In your second example, Class1 is not immutable, as you can mutate the value of Struct2 like this
var foo = new Class1();
foo.Struct2 = new Struct2("a", 1);
foo.Struct2 // returns a copy of Struct2("a", 1);
foo.Struct2 = new Struct2("b", 2);
foo.Struct2 // returns a copy of Struct2("b", 2);
Struct2 is immutable, as there is no way for calling code to change the values of StrVar or InVar once. InStruct is similarly immutable. However, Array is not immutable. So InStruct is an immutable container for a mutable value. Similar to if you had a ImmutableList<List<string>>. While you can guarantee calling code does not change the value of InStruct.StrArray to a different array, you can do nothing about calling code changing the value of the objects in the Array.
Finally, some generic advice related to your example.
First, mutable structs, or structs with mutable fields, are bad. The examples above should point to why structs with mutable fields are bad. And Eric Lippert himself has a great example of how terrible mutable structs can be on his blog here
Second, for most developers working in C# there's almost never a reason to create a user defined value type (i.e. a struct). Objects of value types are stored on the stack, which makes memory access to them very fast. Objects of reference types are stored on the heap, and so are slower to access. But in the huge majority of C# programs, that distinction is going to be dwarfed by the time cost of disk I/O, network I/O, reflection in serialization code, or even initialization and manipulation of collections. For ordinary developers who aren't writing performance-critical standard libraries, there's almost no reason to think about the performance implications of the difference. Heck, developers in Java, Python, Ruby, Javascript and many other languages get by in languages totally without user-defined value types. Generally, the added cognitive overhead they introduce for developers is almost never worth any benefit you might see. Also, remember that large structs must be copied whenever they are passed or assigned to a variable, and can actually be a performance problem.
TL;DR you probably shouldn't use structs in your code, and they don't really have anything to do with immutability.

Equivalent (or better) C# structures to C++ structures

I am a C++ programmer moving to C# (so complete newb really). So far its a pretty easy transition :)
I am porting some code (well, re-writing it) from C++ to C#. I am stuck with lots of possibilities on how to port the following C++ STL structures. Here is a C++ code snippet of my C++ structure layout (I have not bothered showing the enums to save on clutter, but I can add if required):
struct DeviceConnection_t
{
DeviceType_e device;
DeviceState_e state;
bool isPass;
DeviceConnection_t() :
device(DEV_TYPE_UNKNOWN),
state(DEV_STATE_DISCONNECTED),
isPass(false)
{}
};
struct Given_t
{
std::string text;
std::vector<DeviceConnection_t> deviceConnections;
};
struct Action_t
{
ActionEventType_e type;
uint32_t repeat_interval;
uint32_t repeat_duration;
DeviceType_e device;
bool isDone;
Action_t() :
type(AE_TYPE_UNKNOWN),
repeat_interval(0),
repeat_duration(0),
device(DEV_TYPE_UNKNOWN),
isDone(false)
{}
};
struct When_t
{
std::string text;
std::multimap<uint32_t, Action_t> actions; // time, action
};
So here I have a vector of DeviceConnection_t, which I have read here: c-sharp-equivalent-of-c-vector-with-contiguous-memory can just be made into a C# List<DeviceConnection_t>. That seems to work, so far so good.
Next is my multimap<int, Action_t> where the int is a time value where duplicate entries are expected/allowed.
I read here: multimap-in-net that there is no equivalent in C#, but there are various implementations out there.
So I could use one of these, but other questions I read like: order-list-by-date-and-time-in-string-format got me thinking there might be a better way to achieve what I want.
What I really want is:
1.A list of Action_t in time order - where time could be an element of Action_t (I removed it as a element in my c++ because it became my multi-map key). I also need to be able to search through the collection to find time values.
2. Some sort of default constructor to populate the default values of a newly instantiated struct, but I can't see how this is done either.
I really like the look of the Dictionary C# class, but I don't think that fits any of my requirements at the moment (might be wrong here).
So my two questions are:
What is the best way to create a time ordered collection of objects?
How can I assign default values to a new instance of a structure? (in the same way a default constructor does in C++)?
By using struct, it is impossible to enforce initial values. No explicit default constructor can be provided and in case of default construction, all values will be initialized with their default value. It is only possible to provide additional constructors, where fields can be initialized. In the example, if AE_TYPE_UNKNOWN and DEV_TYPE_UNKNOWN would be 0, then default initialization would actually be equivalent to your values.
struct Action_t
{
// example constructor, but there will always be a default constructor
public Action_t(ActionEventType_e type, DeviceType_e device)
{
this.type = type;
this.device = device;
this.isDone = false;
this.repeat_interval = 0;
this.repeat_duration = 0;
}
public ActionEventType_e type;
public UInt32 repeat_interval;
public UInt32 repeat_duration;
public DeviceType_e device;
public bool isDone;
}
If you need to enforce initialization with values that differ from the default, then you need to create a class, where explicit initialization is possible.
class Action_t
{
public ActionEventType_e type = ActionEventType_e.AE_TYPE_UNKNOWN;
public UInt32 repeat_interval = 0;
public UInt32 repeat_duration = 0;
public DeviceType_e device = DeviceType_e.DEV_TYPE_UNKNOWN;
public bool isDone = false;
}
However, for more flexibility I'd advice to use public properties, either as auto properties or as public properties with private backing field. Depending on your choice and used language standard version, you have different options how to write the properties and the initialization:
class Action_t
{
public Action_t()
{
repeat_interval = 0;
}
public UInt32 repeat_interval { get; set; }
private UInt32 _repeat_duration = 0;
public UInt32 repeat_duration
{
get { return _repeat_duration; }
set { _repeat_duration = value; }
}
public bool isDone { get; set; } = false; // valid for C# 6
}
You should read into the differences between struct and class in C#, since there are some mayor differences that you may not expect as a C++ programmer, where struct is basically a public-default class. Then decide, if struct is suited for your case.
The best equivalent to a sorted multimap would probably be a SortedDictionary<key, ICollection<values>> with an add method that handles new keys / adding to existing keys.
IDictionary<DateTime, ICollection<Action_t>> actions = new SortedDictionary<DateTime, ICollection<Action_t>>();
void AddAction(DateTime key, Action_t action)
{
ICollection<Action_t> values;
if (!actions.TryGetValue(key, out values))
{
values = new List<Action_t>();
actions[key] = values;
}
values.Add(action);
}
Unfortunately C# doesn't seem to have a sorted List. The Dictionary is fine if you have Key, Value pairs.
1) If its just a collection (List) you can take a look at the discussion here:
Is there a SortedList<T> class in .NET?. Otherwise you can manually sort the collection(I named it sort in my example) like:
actions.Sort((x, y) => x.time.CompareTo(y.time));
In this your time object should be a IComparable or a primitive, but you can replace "x.time.CompareTo" to any other sorting method. (Based on: List<> OrderBy Alphabetical Order).
If you use a list you can just search the collection with linq:
actions.First(x=>x.time.certainValue == DesiredValue);
But there are many functions to search through the tree. There are some displayed: https://msdn.microsoft.com/en-us/library/system.linq.enumerable_methods(v=vs.110).aspx
2) There are multiple ways to do this. First off, the default constructor:
Action_t() {
type=AE_TYPE_UNKNOWN;
repeat_interval=0;
repeat_duration=0;
device= DEV_TYPE_UNKNOWN);
isDone = false;
}
This works like any other code. But if all values are public Properties (Also a variable: https://msdn.microsoft.com/nl-nl/library/x9fsa0sw.aspx) then you can remove the constructor (or have a public one that you can access) and create new instances with:
new Action_t {
type=AE_TYPE_UNKNOWN,
repeat_interval=0,
repeat_duration=0,
device= DEV_TYPE_UNKNOWN),
isDone = false
}
The difference is where the variables are set. The default constructor is always safe.
I hope this answers your question!

Data type for a variable that can be different types

I am new to C# but seem to have noticed a limitation from what I am wanting to do with my code.
I have a class which i want to store a reference to other classes which i plan to store in a list. Something like this:
myList.Add(new Node(1,1,referenceToClassA));
myList.Add(new Node(1,2,referenceToClassB));
So my class would look like this:
public class Node : IHeapItem<Node> { //IHeapItem is for a heap i use for pathfinding
public int x;
public int y;
public ??? reference;
// constructor
public Node(int a, int b , ??? r){
x = a;
y = b;
reference = r;
}
// other unrelated stuff
}
So as you can probably guess, i have no idea what data type reference would be in my class given that it could be assigned to different classes.
I can't seem to find if there is a data type that is flexible for this in C# (i started in JavaScript so am not used to strict behavior on variable types).
What are my options here, what data type should I use, or will i have to implement this in a totally different way?
Hope you can help.
IF you only have one type of item in each list, then you could use this:
public class Node<T> : IHeapItem<Node> { //IHeapItem is for a heap i use for pathfinding
public int x;
public int y;
public T reference;
// constructor
public Node(int a, int b , T r){
x = a;
y = b;
reference = r;
}
// other unrelated stuff
}
If you don't know what you're going to get, and you will have more than one item in a list, then you're forced to use object. With a little reflection, that can work out pretty well.
It is also possible that you will have sets of different items, each set could implement the same interface, then that interface could be what you hold in the list.
If you're trying to create a generic, use T as the parameter type.
If you use T as the parameter type, you'll have to modify your class to be Node<T> as well.
Otherwise, you could use dynamic.
There is a class called Object that can reference any other class. If you want to make it just to a little group of classes, you may want to create an abstract class or an interface.

Unexpected behavior with Struct internal values

*Solved. Thanks for the explanations guys, I didn't fully understand the implications of using a value type in this situation.
I have a struct that I'm using from a static class. However, the behavior is showing unexpected behavior when I print it's internal state at runtime. Here's my struct:
public struct VersionedObject
{
public VersionedObject(object o)
{
m_SelectedVer = 0;
ObjectVersions = new List<object>();
ObjectVersions.Add(o);
}
private int m_SelectedVer;
public int SelectedVersion
{
get
{
return m_SelectedVer;
}
}
public List<object> ObjectVersions;//Clarifying: This is only used to retrieve values, nothing is .Added from outside this struct in my code.
public void AddObject(object m)
{
ObjectVersions.Add(m);
m_SelectedVer = ObjectVersions.Count - 1;
}
}
Test code
VersionedObject vo = new VersionedObject(1);
vo.AddObject(2);//This is the second call to AddObject()
//Expected value of vo.SelectedVerion: 1
//Actual value of vo.SelectedVersion: 1
Now, if you test this code in isolation, i.e., copy it into your project to give it a whirl, it will return the expected result.
The problem; What I'm observing in my production code is this debug output:
objectName, ObjectVersions.Count:2, SelectedVer:0,
Why? From my understanding, and testing, this should be completely impossible under any circumstances.
My random guess is that there is some sort of immutability going on, that for some reason a new struct is being instanced via default constructor, and the ObjectVersions data is being copied over, but the m_SelectedVersion is private and cannot be copied into the new struct?
Does my use of Static classes and methods to manipulate the struct have anything to do with it?
I'm so stumped I'm just inventing wild guesses at this point.
Struct is value type. So most likely you are creating multiple copies of your object in your actual code.
Consider simply changing struct to class as content of your struct is not really good fit for value type (as it is mutable and also contains mutable reference type).
More on "struct is value type":
First check FAQ which have many good answers already.
Value types are passed by value - so if you call function to update such object it will not update original. You can treat them similar to passing integer value to function: i.e. would you expect SomeFunction(42) to be able to change value of 42?
struct MyStruct { public int V;}
void UpdateStruct(MyStruct x)
{
x.V = 42; // updates copy of passed in object, changes will not be visible outside.
}
....
var local = new MyStruct{V = 13}
UpdateStruct(local); // Hope to get local.V == 42
if (local.V == 13) {
// Expected. copy inside UpdateStruct updated,
// but this "local" is untouched.
}
Why is this a struct and not a class? Even better, why are you tracking the size of the backing store (List<T>) rather than letting the List<T> track that for you. Since that underlying backing store is public, it can be manipulated without your struct's knowledge. I suspect something in your production code is adding to the backing store without going through your struct.
If it were me, I'd set it up something like this, though I'd make it a class...but that's almost certainly a breaking change:
public struct VersionedObject
{
public VersionedObject()
{
this.ObjectVersions = new List<object>() ;
return ;
}
public VersionedObject(object o) : this()
{
ObjectVersions.Add(o);
return ;
}
public VersionedObject( params object[] o ) : this()
{
ObjectVersions.AddRange( o ) ;
return ;
}
public int SelectedVersion
{
get
{
int value = this.ObjectVersions.Count - 1 ;
return value ;
}
}
public List<object> ObjectVersions ;
public void AddObject(object m)
{
ObjectVersions.Add(m);
return ;
}
}
You'll note that this has the same semantics as your struct, but the SelectedVersion property now reflects what's actually in the backing store.

Categories