Can someone explain this C# syntax? - c#

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

Related

Default value in string property [duplicate]

I'm trying to make default value for my struct.
For example default value for Int - 0, for DateTime - 1/1/0001 12:00:00 AM.
As known we can't define parameterless constructor in structure.
struct Test
{
int num;
string str;
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(default(Test)); // shows namespace and name of struct test.Test
Console.WriteLine(new Test()); // same
Console.ReadKey(true);
}
}
How can I make a default value for struct?
You can't. Structures are always pre-zeroed, and there is no guarantee the constructor is ever called (e.g. new MyStruct[10]). If you need default values other than zero, you need to use a class. That's why you can't change the default constructor in the first place (until C# 6) - it never executes.
The closest you can get is by using Nullable fields, and interpreting them to have some default value if they are null through a property:
public struct MyStruct
{
int? myInt;
public int MyInt { get { return myInt ?? 42; } set { myInt = value; } }
}
myInt is still pre-zeroed, but you interpret the "zero" as your own default value (in this case, 42). Of course, this may be entirely unnecessary overhead :)
As for the Console.WriteLine, it simply calls the virtual ToString. You can change it to return it whatever you want.
Your problem is not with the behaviour of C#/.Net. The way you instantiate the struct effectively creates an instance with default values for all member fields.
The Console.WriteLine converts its argument to a string using the ToString() method. The default implementation (Object.ToString()) simply writes the fully qualified class name (namespace and name, as you call it).
If you want another visualisation, you should override the ToString method:
public struct Test
{
int num;
string str;
public override string ToString()
{
return $"num: {num} - str: {str}";
}
}
This is my take on this in case somebody finds it useful.
public struct MyStruct
{
public int item1;
public float item2;
public float item3;
public static MyStruct Null => new MyStruct(-1, 0, 0);
}
I have a static method inside my struct so that I can do this:
var data = MyStruct.Null;
instead of
var data = new MyStruct();
data.item1 = -1;
...
Or create a custom constructor to pass the data.
Printing out objects of the C# results with namespaces unless you override .ToString() for your objects. Can you define your struct like below and try it ?
public struct Test
{
int num;
string str;
public override string ToString()
{
return "Some string representation of this struct";
}
}
PS: default(Test) gives you a struct contains default(int) and default(string) which I mean Test.num is 0 and Test.str is null
Hope this helps
You can also do this:
public struct MyStruct
{
public static readonly Default = new MyStruct(42);
public int i;
public MyStruct(int i)
{
this.i = i;
}
}
And then when you create a default struct of this type do this:
public MyStruct newStruct = MyStruct.Default;
But of course, this won't override default and other programmers will bump their heads a few times. Really consider if a struct is the way to go, from the microsoft docs:
"A structure type (or struct type) is a value type that can encapsulate data and related functionality. Typically, you use structure types to design small data-centric types that provide little or no behavior."
Consider this: if you had 2 values in your struct and you wanted to make constructors, would 2 or less constructors suffice? If the answer is no, then the answer is: don't use a struct.
What you probably want to do is to override ToString(), e.g.
struct Test
{
int num;
string str;
public override string ToString ()
{
return string.Format ($"{str} | {num}");
}
}
As you have mentioned, it is impossible to define default values for fields other than default values for their appropriate types. However, with an overriden ToString(), you will see better formatted information about your structure in the console and during debugging.

Class template with value in C#

Is there any type of template that can be used like the statement below:
BitSet<10> bitSet; //we can create bitset with n bits, here is 10
bool b = bitSet.get<3>(); //get value of bit 3rd.
And how can I define a class like this in C#?
You should use a simple class, with a Constructor parameter (10) and then just call any method that recall any bit. Templates are for datatypes afaik. Anyway, look at This answer to verify if thats what you are looking for (Constructor parameter with a template with a given type)
c# code is :
bool[] array = new bool[]{true,false,false,true,false,false};
System.Collections.BitArray bitArray = new System.Collections.BitArray(array);
Console.WriteLine(bitArray[3]);
Not exactly like what you want but you can do that kind of stuff by using Indexers.
class BitSet
{
private bool[] _bits;
public BitSet(int length)
{
_bits = new bool[length];
}
public bool this[int index]
{
get
{
return _bits[index];
}
set
{
_bits[index] = value;
}
}
}
To use that class
BitSet bitset = new BitSet(10);
bitset[0] = true;
Console.WriteLine(bitset[0]);

What the difference between array indexer and any other object indexer

Consider following two data types:
class C
{
public int I { get; set; }
}
struct S
{
public int I { get; set; }
}
Let's try to use them inside the list, for example:
var c_list = new List<C> { new C { I = 1 } };
c_list[0].I++;
var s_list = new List<S> { new S { I = 1 } };
s_list[0].I++; // (a) CS1612 compilation error
As expected, there is compilation error on line (a): CS1612 Cannot modify the return value of 'List<UserQuery.S>.this[int]' because it is not a variable. This is fine, because actually we trying to modify temporary copy of S, which is r-value in giving context.
But let's try to do same thing for an array:
var c_arr = new[] { new C { I = 1 } };
c_arr[0].I++;
var s_arr = new[] { new S { I = 1 } };
s_arr[0].I++; // (b)
And.. this works.
But
var s_arr_list = (IList<S>) s_arr;
s_arr_list[0].I++;
will not compile, as expected.
If we look at the produced IL, we will find following:
IL_0057: ldloc.1 // s_arr
IL_0058: ldc.i4.0 // index
IL_0059: ldelema UserQuery.S // manager pointer of element
ldelema loads address of the array element to the top of the evaluation stack. Such behavior is expected with fixed array and unsafe pointers. But for safe context this is a bit unexpected. Why there is a special unobvious case for arrays? Any why there is no option to achieve same behavior for members of other types?
An array access expression is classified as a variable. You can assign to it, pass it by reference etc. An indexer access is classified separately... in the list of classifications (C# 5 spec section 7.1.)
An indexer access. Every indexer access has an associated type, namely the element type of the indexer. Furthermore, an indexer access has an associated instance expression and an associated argument list. When an accessor (the get or set block) of an indexer access is invoked, the result of evaluating the instance expression becomes the instance represented by this (§7.6.7), and the result of evaluating the argument list becomes the parameter list of the invocation.
Think of this as similar to the difference between a field and a property:
public class Test
{
public int PublicField;
public int PublicProperty { get; set; }
}
...
public void MethodCall(ref int x) { ... }
...
Test test = new Test();
MethodCall(ref test.PublicField); // Fine
MethodCall(ref test.PublicProperty); // Not fine
Fundamentally, an indexer is a pair of methods (or a single one) whereas an array access gives you a storage location.
Note that if you weren't using a mutable struct to start with, you wouldn't see the difference in this way - I'd strongly advise against using mutable structs at all.
A class indexer like the one in List<T> is actually a syntactically convenient way of calling a method.
With arrays however you are actually accesing to the structure in memory. There is no method call in that case.

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; }
}

Make object that encapsulates List<> accessable via [] operator?

I have a class that I made that is basically an encapsulated List<> for a certain type. I can access the List items by using [] like if it was an array, but I don't know how to make my new class inherit that ability from List<>. I tried searching for this but I'm pretty sure I don't know how to word correctly what I want to do and found nothing useful.
Thanks!
That's called an indexer:
public SomeType this[int index] {
get { }
set { }
}
List already have a definition for the Indexer so there is no need to change that code. It will work by default.
public class MyClass : List<int>
{
}
And we can access the indexer here. Even though we havent implemented anything
MyClass myclass = new MyClass();
myclass.Add(1);
int i = myclass[0]; //Fetching the first value in our list ( 1 )
Note that the List class isn't designed to be inherited. You should be encapsulating it, not extending it. – Servy
And this would look something like
public class MyClass
{
private List<int> _InternalList = new List<int>();
public int this[int i]
{
get { return _InternalList[i]; }
set { _InternalList[i] = value; }
}
}
That's called 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.
Indexers enable objects to be indexed in a similar manner to arrays.
A get accessor returns a value. A set accessor assigns a value.
The this keyword is used to define the indexers.
The value keyword is used to define the value being assigned by the set indexer.
Here is an EXAMPLE.

Categories

Resources