How to Overload the Square-Bracket Operator in C#

How do I overload the square-bracket operator in C#?

you can find how to do it here.
In short it is:

public object this[int i]
{
get { return InnerList[i]; }
set { InnerList[i] = value; }
}

If you only need a getter the syntax in answer below can be used as well (starting from C# 6).

Override the square bracket operator of string?

Let's deal with a couple of concepts one at a time.

The square bracket operators are used for indexing into aggregate objects:

  • Arrays
  • Indexer properties on objects

Additionally they're used to denote attributes but this is not relevant to this answer.

Now, a string is not an array and thus the string object has a this[...] property.

Your question: "how can I override the square bracket operator?" has this answer: Simply put, you override like any other property, provided that you can:

  1. Inherit from the type that declared it
  2. Override it because it is virtual
  3. Actually get the effect because you can have code use your new descendant type when constructing objects instead of the original base type

For strings, the criteria are all a no-go for this:

  1. You can't inherit from strings, it is a sealed type, and contains mostly external code for performance considerations
  2. Since the type is sealed, there is no point in having virtual members
  3. You can't substitute the use of the System.String type when constructing strings in large swats of the code.

So override this for strings? Nope, can't be done.

Then you show an example what you came up with, which is similar to the syntax of an extension method.

To recap before continuing:

  • To override something, we talk about inheritance and polymorphism (virtual member in base class)
  • To extend something with an extension method you can provide on-the-side extra methods to existing types without modifying said types

And yes, you can surely add extension methods to strings, but you can't provide extension properties (yet).

The new Roslyn compiler project has a lot of features suggested for it, including an Extension Everything feature which could possibly solve this. It is, however, not yet decided upon nor planned nor implemented.

You can create a normal extension method, you just can't redefine, override, or extend, what the [...] operators do.

public static class StringExtension
{
public static char CharAt(this string value, int position)
{
//do something
}
}

Usage:

string s = "Test";
char c = s.CharAt(2);

How do I overload the [] operator in C#


public int this[int key]
{
get => GetValue(key);
set => SetValue(key, value);
}

Overload Bracket[] operator for a List object

you can use approach like this

public class MapInfo {
private readonly TableCollection _tables = new TableCollection();

public TableCollection Tables {
get { return _tables; }
}
}

public class TableCollection : List<Table> {
public Table this[string name] {
get { return this.FirstOrDefault(t => t.Name == name); /*using System.Linq;*/ }
}
}

public class Table {
public string Name { get; set; }
}

or simply use a dictionary (Dictionary<string, Table>) as Danaldo suggested. but not BOTH of them as he'd coded =))

IMO, the right way is not to use indexers like these, cause as I see there can be more than one table with 'unique' name in your collections. I'd recommend using a simple List of Tables and a method like GetTableWithName to make things clearer because indexers usually give a (false) hope that that your data is unique

OR you can replace a call to FirstOrDefault with SingleOrDefault which will internally ensure that if there is an element with the 'name' no other element has the same 'name'

C# - How to overload [][] (two square brakets)

To get an indexed property that looks like that you'd need to do

public class YourClass
{
private double[][] _elements;

public double[] this[int index]
{
get
{
return _elements[index];
}
set
{
_elements[index] = value;
}
}
}

That would allow something like

var instance = new YourClass();
var d = instance[0][1];
instance[0][1] = 2.5;

Though at this point you'd need to be vary careful about your index ranges and should probably expose _element.Length in another property.

Square bracket [] operator overloading c++


New Answer

I have to rewrite my answer, my old answer is a disaster.

The check should happen during the assignment, when the right hand side (11) is available. So the operator which you need to overload is operator=. For overloading operator=, at least one of its operands must be an user defined type. In this case, the only choice is the left hand side.

The left hand side we have here is the expression a[i]. The type of this expression, a.k.a the return type of operator[], must be an user defined type, say BigNumberElement. Then we can declare an operator= for BigNumberElement and do the range check inside the body of operator=.

class BigNum {
public:
class BigNumberElement {
public:
BigNumberElement &operator=(int rhs) {
// TODO : range check
val_ = rhs;
return *this;
}

private:
int val_ = 0;
};

BigNumberElement &operator[](size_t index) {
return element_[index];
}

BigNumberElement element_[10];
};

OLD answer

You can define a wapper, say NumWapper, which wraps a reference of BigNum's element. The operator= of BigNum returns the wrapper by value.

a[i]=11;

is then something like NumWrapper x(...); x = 11. Now you can do those checks in the operator= of NumWrapper.



class BigNum {
public:
NumWrapper operator[](size_t index) {
return NumWrapper(array_[index]);
}

int operator[](size_t index) const {
return array_[index];
}
};

In the NumWrapper, overload some operators, such as:

class NumWrapper {
public:
NumWrapper(int &x) : ref_(x) {}
NumWrapper(const NumWrapper &other) : ref_(other.ref_) {}

NumWrapper &operator=(const NumWrapper &other);
int operator=(int x);
operator int();

private:
int &ref_;
};

You can also declare the NumWrapper's copy and move constructor as private, and make BigNum his friend, for preventing user code from copying your wrapper. Such code auto x = a[i] will not compile if you do so, while user code can still copy the wrapped value by auto x = static_cast<T>(a[i]) (kind of verbose though).

auto &x = a[i]; // not compiling
const auto &x = a[i]; // dangerous anyway, can't prevent.

Seems we are good.


These is also another approach: store the elements as a user defined class, say BigNumberElement. We now define the class BigNum as :

class BigNum {
// some code
private:
BigNumberElement array_[10];
}

We need to declare a whole set operators for BigNumberElement, such as comparison(can also be done through conversion), assignment, constructor etc. for making it easy to use.

auto x = a[i] will now get a copy of BigNumberElement, which is fine for most cases. Only assigning to it will sometimes throw an exception and introduce some run-time overhead. But we can still write auto x = static_cast<T>(a[i]) (still verbose though...). And as far as I can see, unexpected compile-time error messages is better than unexpected run-time exceptions.

We can also make BigNumberElement non-copyable/moveable... but then it would be the same as the first approach. (If any member functions returns BigNumberElement &, the unexpected run-time exceptions comes back.)

Overload [] operator in C# and give more than one return value

In c# these are called indexers.

Syntax:

public object this[int key]
{
get
{
return GetValue(key);
}
set
{
SetValue(key,value);
}
}

You can return only one object. Use a base class instead for all the type objects you have to return.

Is there any way to overload the += operator in C#

You just need to overload the + operator because += is just a syntactic sugar, e.g:

x += 1

is equivalent to

x = x + 1;


Related Topics



Leave a reply



Submit