Modify a struct within a List - c#

Working with
private struct Emitter
{
public string COM;
public string FW_Version;
public string DAE_Version;
};
private List<int> EmitterToBootload;
private int EmitterToBootloadIndex;
private List<Emitter> Emitters;
I get "Cannot modify the return value of 'List<namespace.Emitter>.this[int]' because it is not a variable"
For this code
Emitters[EmitterToBootload[EmitterToBootloadIndex]].FW_Version = fw;
I tried this workaround, is it correct ?
Emitter em = Emitters[EmitterToBootload[EmitterToBootloadIndex]];
em.FW_Version = fw;
Emitters[EmitterToBootload[EmitterToBootloadIndex]] = em;
Can someone explain to me what's wrong with my first code ?

Since the struct is a value type and not a reference type, the list indexer returns a copy of the struct and not a reference to the struct in the list.
If you could modify this struct, it would only affect your local copy and the struct in the list would remain unchanged.
Note that this is different for arrays because indexing an array yields the very position inside the array.
The list indexer is implemented like this:
public T this[int index] {
get {
// Following trick can reduce the range check by one
if ((uint) index >= (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException();
}
Contract.EndContractBlock();
return _items[index];
}
set {
if ((uint) index >= (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException();
}
Contract.EndContractBlock();
_items[index] = value;
_version++;
}
}
I.e., the getter returns a copy of the value from the internal array with return _items[index];. It is not an alias for the array index.
To avoid this kind of problem, structs should be immutable. Or use a class instead. Classes are reference types and class variables always contain a reference.

Related

How to access methods of subclass in object array C#?

How can I set/get the value of an object in an object array?
Currently I get:
"object does not contain a definition for 'value' and no extension method"
Example C#;
public class myObjClass
{
public int value = 5;
}
public class myObjClass2
{
public float[] pos = new float[2];
}
public void test()
{
myObjClass myObj = new myObjClass();
myObjClass2 myObj2 = new myObjClass2();
object[] objArr = new object[2];
objArr[0] = myObj;
objArr[1] = myObj2;
Debug.Print(myObj.value.ToString());
Debug.Print(objArr[0].value.ToString()); // how?
}
Its because a generic object does not have the property value your class myObjClass has. To fix this you could cast the item to your class like so:
((myObjClass)objArr[0]).value.ToString()
Only do this ^ if you are sure of the type
Instead you could also check it first:
With as:
var item = objArr[0] as myObjClass;
if( item != null ) // Item will be null if its not a 'myObjClass'
{
//Do stuff with item
}
Or with is:
if( objArr[0] is myObjClass )
{
var item = (myObjClass)objArr[0];
//Do stuff with item
}
When using an object array you have to cast to the real type (here: myObjClass) before accessing the fields:
You can access the object like this
((myObjClass)objArr[0]).value
but I would not recommend. CanĀ“t you have your array to be the concrete type
var array = new myObjClass[42]
A compact safe alternative to retrieve the value is
(objArr[0] as myObjClass)?.value
You need to cast object to known type which is myObjClass, like:
((myObjClass)objArr[0]).value.ToString();
Or you can use reflection
var valueString = objArr[0].GetType().GetProperty("value").GetValue(objArr[0]);
Debug.Print(valueString.ToString());
Hope helps,
Technically you can put it as
Debug.Print((objArr[0] as myObjClass)?.value.ToString());
We try casting objArr[0] as myObjClass and if succeed get value and turn it to string. If objArr[0] is not myObjClass we return null as a string
However, a much better way is to implement ToString() in both classes of interest:
public class myObjClass
{
public int value = 5;
public override string ToString() {
// When debugging we want to know "value"
return value.ToString();
}
}
public class myObjClass2
{
public float[] pos = new float[2];
public override string ToString() {
// When debugging we want to know "pos[0]" and "pos[1]" values
return $"{pos[0]} : {pos[1]}";
}
}
And then put an easy
// Just print out debug info (we don't want to know the actual objArr[0] class)
Debug.Print(objArr[0].ToString());
You have a single object, that indeed is an instance of myObjClass, and has a value field, but you have two references to it.
One (myObj) is known to the compiler to be of type myObjClass, and it can guarantee that it has a value field.
The other (objArr[0]) is only known to the compiler to be of type object, and it cannot guarantee that it has a value field.
For example, you could do:
objArr[0] = (random.Next() > 0.5) : myObj ? myObj2
where we're gonna decide at runtime, based on the value of a random number, which will be the type of the actual object at objArr[0].
So, if this was allowed, half of the time objArr[0].value would be correct, and half of the time it will be an error.

Can someone explain this C# syntax?

What's actually going on here:
public decimal[] Coefficients;
public decimal this[int i]
{
get { return Coefficients[i]; }
set { Coefficients[i] = value; }
}
What does the this serve as? Is it some sort of extension to the decimal?
It's an Indexer.
Indexers allow instances of a class or struct to be indexed just like arrays. Indexers resemble properties except that their accessors take parameters.
Example from the linked MSDN:
class SampleCollection<T>
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
// Define the indexer, which will allow client code
// to use [] notation on the class instance itself.
// (See line 2 of code in Main below.)
public T this[int i]
{
get
{
// This indexer is very simple, and just returns or sets
// the corresponding element from the internal array.
return arr[i];
}
set
{
arr[i] = value;
}
}
}
// This class shows how client code uses the indexer.
class Program
{
static void Main(string[] args)
{
// Declare an instance of the SampleCollection type.
SampleCollection<string> stringCollection = new SampleCollection<string>();
// Use [] notation on the type.
stringCollection[0] = "Hello, World";
System.Console.WriteLine(stringCollection[0]);
}
}
// Output:
// Hello, World.
It is an indexer it will be called when you use syntax like obj[1]. https://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
Have you ever wondered how List<T>'s myList[i] works in c# just like an array ?
The Answer is in your question. The syntax you posted is a syntactic sugar that the compiler transforms into properties called get_Item(int index) and set_Item(int index, decimal value). It is used in List<T> for example to access the internal array used in the class and return the element at the specified index (set or get). This feature is called an Indexer.
To test that yourself, try to create a method with same signature :
public decimal get_Item(int i)
{
return 0;
}
You'll get a compiler error :
Error CS0082: Type 'MyClass' already reserves a member called
'get_Item' with the same parameter types

Is it possible to change default value for value types variables? [duplicate]

This question already has answers here:
Is it possible to change the default value of a primitive data type?
(6 answers)
Closed 7 years ago.
I'm just curious to know, is it possible to change default value of e.g. int in C# and I can have a value -1 instead of 0.
public class Foo {
public int i;
}
...
foo = new Foo();
Console.Write(foo.i);
so this code must return
-1
Without explicit initializing
public class Foo {
public int i = -1;
}
Can I always be sure, that someone don't print somewhere something like
#define TRUE FALSE
but for default value of int
P.S. for interest purposes only.
No, basically. Assuming you don't initialize fields, the memory space is simply zeroed. You shouldn't expose fields directly anyway.
One trick I have seen to get around this (used by the capnp serializer, which works against raw memory, not objects) is to use xor. For example: if the default is -1, you can xor the value in and out:
public class Foo {
private int i;
public int I {
get { return i ^ -1; }
set { i = value ^ -1; }
}
}
This has no initialization, and does what you want. For use with types other than bools and integers this is more complex, but still possible - but it would be easier to use an initializer.
Note that for the -1 case, you could use "not" rather than "xor":
public class Foo {
private int i;
public int I {
get { return ~i; }
set { i = ~value; }
}
}
However: a field initializer (int i = -1;) or a constructor (public Foo() { i = -1; }) is probably simpler.
You can't change int's default value, but you can set Foo's variables default value:
public class Foo
{
public int i;
public Foo()
{
i = -1;
}
}
As far as I know, you can not change the default value of value types.
But you can certainly initialize it to a value you want.
for eg.
public class Foo {
public int i = -1;
}
...
foo = new Foo();
Console.Write(foo.i);
it will return
-1
A nice solution would be to override default(T), but you can't override this keyword. It is always null for reference types and zero for value types.

How implement an array property that does not simply encapsulate a field?

I want to implement a property that returns a value based on the index it receives. I am not just encapsulating a private array. In fact, the data I will be returning is not stored in any arrays, but instead stored in member objects. This array property will simply be a way to access this data in an indexed way without needing to store it in an indexed way.
According to this article, the following should work:
public double Angles[int i]
{
get { // return a value based on i; }
}
I get the following error, however:
The type or namespace 'i' could not be found (are you missing a using directive or an assembly reference?)
Invalid token ']' in class, struct or interface member declaration
Invalid expression term 'int'
Bad array declarator: To declarate a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type.
Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
From those errors, I think it seems that the compiler thinks I am attempting to create an array member. Obviously my syntax is wrong here. Can anybody tell me the correct way to do this?
Named indexers do not exist in C#. You can, however, add Angles as some type of object that has an indexer, i.e.
public class Foo {
public Angles Angles { get { return angles; } }
...
}
...
public class Angles {
public double this[int index] { get { ... } }
...
}
Or if you want the implementation in one class:
public class Foo : IAngles {
public IAngles Angles { get { return this; } }
double IAngles.this[int index] { get { ... } }
}
public interface IAngles {
double this[int index] { get;}
}
The method has to looke like that:
public double this[int i]
{
get { // return a value based on i; }
}

how can i do binary search on an array of structs w.r.t a particular field value in c#?

I have an array of structs, where the struct has three integer fields. It is sorted by one of the fields, say F, and I want a way to do a binary search with respect to this field, that is, a function of the form binarySearch(mystruct[] myarray, int val) which returns the index of the structure in which field F = val. I know that there is an existing Array.BinarySearch(T[] array, T value) function, but it only allows to search for a type T that is the same as the types in the array. This means that if I want to search with respect to a value, I need to create a new struct and set field F to that value just so that I can pass it to this function. I don't think there would be significant performance overhead but it seems ugly. The other way I can think is to implement the function myself, but this also seems inelegant when something so similar exists. Any suggestions for a better way or which way would be preferred?
You can either implement IComparable<T> for your struct to compare on the field (F), or you can create an IComparer<> for your struct that will compare based on that field and pass that into Array.BinarySearch().
So either:
// using IComparable<T>
public struct MyStruct : IComparable<MyStruct>
{
public int F { get; set; }
// other fields that should not affect "search"
public int X { get; set; }
public int CompareTo(MyStruct other)
{
return F.CompareTo(other.F);
}
}
Which can be called as:
MyStruct target = new MyStruct { F = 13 };
Array.BinarySearch(arrayOfMyStruct, target);
Or a separate IComparer<MyStruct>:
public struct MyStruct
{
public int F { get; set; }
// other non-sort/search affecting properties
public int X { get; set; }
}
public struct MyStructComparer : IComparer<MyStruct>
{
public int Compare(MyStruct x, MyStruct y)
{
return x.F.CompareTo(y.F);
}
}
Which can be called like:
MyStruct target { F = 13; }
Array.BinarySearch(myArrayOfStruct, target, new MyStructComparer());
The first has less code, but it strongly couples ordering to the type, which if you want to alter ordering based on situation (that is, allow multiple sort orders), this isn't ideal. The latter gives more flexibility in that you can provide multiple different orders independent of the struct, but it does require an extra class.
UPDATE
If you don't want to create a dummy struct to compare against, you can implement IComparable like:
public struct MyStruct : IComparable
{
public int F { get; set; }
// other non-sort/search affecting properties
public int X { get; set; }
public int CompareTo(object other)
{
// if the type is NOT an int, you can decide whether you'd prefer
// to throw, but the concept of comparing the struct to something
// unknown shouldn't return a value, should probably throw.
return F.CompareTo((int)other);
}
}
Which could be called like:
Array.BinarySearch(arrayOfMyStruct, 13);
But again, this strongly ties your implementation of the class to a given comparison type, which I think is uglier than using a dummy search target, but that's my personal preference. Personally, especially with initializer syntax being as short as it is, I prefer to use the dummy target:
var target = new MyStruct { F = 13 };
UPDATE: You can support both int and MyStruct comparissons, but it gets messy quickly, which is why I personally, again, recommend using the dummy struct to avoid the headaches:
// implement IComparable<int> for the int search (w/o dummy), and IComparable<MyStruct> for sort
public struct MyStruct : IComparable, IComparable<MyStruct>, IComparable<int>
{
public int F { get; set; }
// other non-sort/search affecting properties
public int X { get; set; }
public int CompareTo(object other)
{
if (other is int)
return F.CompareTo((int)other);
if (other is MyStruct)
return F.CompareTo((MyStruct)other);
throw new InvalidOperationException("Other must be int or MyStruct.");
}
public int CompareTo(MyStruct other)
{
return F.CompareTo(other.F);
}
public int CompareTo(int other)
{
return F.CompareTo(other);
}
}
If your struct implements IComparable, you can use:
// myValue is an the value of the field to compare to
Array.BinarySearch(myArray, myValue);
as described in http://msdn.microsoft.com/en-us/library/y15ef976.aspx
You can compare a struct to an object with IComparable, so you can pass in the value intead of a new struct. In your implementation of CompareTo, you can compare any value with the field value, allowing you to say 'My struct should be considered greater/less than this number'.
EDIT:
Here is an example of CompareTo for your struct:
public int CompareTo(object obj)
{
if (obj is int)
{
return myIntField.CompareTo((int)obj);
}
return 0;
}
One way would be to create a custom IComparer<T> that compares instances of your struct based only on the value of that field and pass it to this overload of BinarySearch (you will also need to create a "dummy" struct instance to compare to). This is probably the purest solution.
However, as a practical matter you can use LINQ to project into a collection of field values and binary search into that; the resulting index will be the same as if you had searched the struct collection itself. For example:
var structs = new MyStruct[n];
var index = structs.Select(i => i.F).ToList().BinarySearch(42);
In the code above, F is the vame of the field and 42 is the value you are searching for (its type would be the type of F). This is not going to be as fast, but you don't need to write any code and speed could very well be irrelevant in your case.
Update: To clarify: obviously, the code above will be O(n) due to the projection operation so using binary search once after projecting like that is silly (you can simply do a linear search instead). However, if you intend to make multiple searches then it might start making sense.
I would definitely not recommend overriding Equals in your struct unless comparisons between instances are meant to be reduced to comparing F members everywhere in your application.

Categories

Resources