C# allows you to override the array indexer of the this property, like so:
int this[int index]
{
get { return _hidden[index]; }
set { _hidden[index] = value; }
}
int[] _hidden;
However, I'd like to access a differently named property via an index, like so:
int Hidden[int index]
{
get { return _hidden[index]; }
set { _hidden[index] = value; }
}
int[] _hidden;
I know I could work around this by using it as a regular parameter, as such:
int Hidden(int index)
{
return _hidden[index];
}
void Hidden(int index, int value)
{
_hidden[index] = value;
}
int[] _hidden;
However, I lose the convenience of a named property that way, and I'm essentially returning to publicly named get/set methods. Additionally, as I am behind the scenes accessing members of an array, the array indexing notation makes more sense conceptually for my situation.
Is there any way to combine the convenience of the operator with the array indexer?
A property cannot behave like an indexable item, unless it returns one. You have two options:
return an array, list or other item that you already have behind the scenes
create an object that provides an indexer and returns the values
The first one is simple, but it will allow changing the array/list/whatever. The second one can have only a getter, so it can be made read only.
I'm pretty sure it wouldn't be many lines of code to make a generic template with indexer and getter to encapsulate the actual object storing the values if it is needed.
Related
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
first off - yes, I had a look at this question: Is object creation in getters bad practice?.
I am also not talking about initializing an object in the accessors / mutators, it is about a specific part of the object I want to be returned in a specific way.
My question is more specific; It does not necessarily only apply to C#, however I am currently looking for a solution to implement in my C# project.
I have a class with a dictionary that maps date objects to a decimal value. In one accessor, I want to return a list of all the keys of the dictionary, another accessors returns the values.
What I also want to have is an accessor that gives me the decimal values in a specific format. It would look something like this:
class Class
{
// Some other properties...
// ....
private Dictionary<DateTime, decimal> dict;
public Class(Dictionary<DateTime, decimal> dict)
{
this.dict = dict;
}
private string FormatTheWayIWant(decimal dt)
{
// Format decimal value.
string s = String.Format("{0:F}", dt);
return s;
}
public ReadOnlyCollection<DateTime> DateTimes
{
get { return new ReadOnlyCollection<DateTime>(this.dict.Keys.ToList()); }
}
public ReadOnlyCollection<decimal> Values
{
get { return new ReadOnlyCollection<decimal>(this.dict.Values.ToList()); }
}
public ReadOnlyCollection<string> FormattedStrings
{
get
{
// Format each decimal value they way I want.
List<string> list = new List<string>();
foreach (decimal dt in dict.Keys)
{
list.Add(FormatTheWayIWant(dt));
}
return new ReadOnlyCollection<string>(list);
}
}
}
This way I can make the following calls (which is my goal!):
DateTime dateTime = DateTimes[0];
decimal s = Values[0];
string formattedS = FormattedStrings[0];
The problem with this approach is that I create a new list everytime I invoke the FormattedStrings accessor, even if I only need one of the formatted strings. I know this is not good practice and can introduce unnecessary performance issues...
The alternatives I thought of are:
I could extend the decimal class and implement a custom ToString()-method.
Or overwrite the KeyValuePair<DateTime, decimal> class and use an indexer in my class.
Or I create a method with a parameter for the index and return just the one formatted string.
Or I could have an own list for the accessor, which gets updated in the set-method for my dictionary everytime I update the dictionary.
The question I have is, is there a way to make this work with an accessor instead of a method, creating custom classes or having strange side effects on other objects when assigning a value?
Thank you in advance.
Ofcourse this can be done with an accessor. You just have to create 3 separate classes for each desired element of your processed collection. Those classes should have their own indexers, so you would be able to access the elements as a list. The difference would be, that they compute each element on demand (wchich is called lazy initialization). So it would go like this (example for your FormattedStrings):
class Class
{
// ...
MyFormattedStrings FormattedStrings
{
get {return new MyFormattedStringsIndexer<string>(this.dict.Values.ToList());}
}
}
class MyFormattedStringsIndexer<T>
{
private IList<T> list; // we take only reference, so there is no overhead
public MyFormattedStringsCollection (IList<T> list)
{
this.list = list;
}
// the indexer:
public T this[int i]
{
get
{
// this is where the lazy stuff happens:
// compute the desired element end return it
}
set
{
// ...
}
}
}
Now you can use your Class like this:
string formattedS = FormattedStrings[5];
and each element you access will be computed as you access it. This solution also has the advantage of separating concerns, so should you ever had to implement different logic for one of your 3 accessors it would be just a matter of extending one of the indexers.
You can read more about indexeres here: http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
This is VB, but you get the idea...
Public Class Something
Public Property Items As Dictionary(Of DateTime, String)
Public Readonly Property FormattedItem(ByVal index As Int32) As String
' add error checking/handling as appropriate
Return Me.Items.Keys(index).ToString("custom format") ' or whatever your formatting function looks like.
End Property
End Class
It looks like a good candidate for a new class
public class MyObject
{
public DateTime Key {get;set;}
public String Name {get;set;}
public String FormattedString {get;}
}
And then it can be used in any container (List<MyObject>, Dictionary<MyObject>, etc).
Your Dates and Strings property getters are returning a new list on each call. Therefore if a caller does the following:
Class myClass = ...
for(i=0; i<myClass.Strings.Count; i++)
{
var s = myClass.Strings[i];
...
}
then each iteration of the loop will create a new list.
I'm not clear on what you're really trying to achieve here. You are wrapping the dictionary's Keys and Values properties in ReadOnlyCollections. This gives you an indexer, which doesn't have much meaning as the order of the Keys in a Dictionary<TKey, TValue> is unspecified.
Coming (at last!) to your question, if you want to do the formatting in a "lazy" manner, you could create a custom class that implements a readonly IList<string>, and wraps your list of keys (IList<DateTime>). Most of the implementation is boilerplate, and your indexer will do the formatting. You could also cache the formatted values so that you only format once if accessed multiple times. Something like:
public class MyFormattingCollection : IList<string>
{
private IList<decimal> _values;
private IList<string> _formattedValues;
public MyFormattingCollection(IList<DateTime> values)
{
_values = values;
_formattedValues = new string[_values.Count];
}
public string this[int index]
{
get
{
var result = _formattedValues[index];
if (result == null)
{
result = FormatTheWayIWant(_values[index]);
_formattedValues[index] = result;
}
return result;
}
set
{
// Throw: it's a readonly collection
}
}
// Boilerplate implementation of readonly IList<string> ...
}
How is this different from a normal property in C#?
public new Point3D this[int index]
{
get { return base[index]; }
set
{
base[index] = value;
CollectionModified();
}
This is an indexer; instead of being used as obj.Foo, it is used as obj[index], i.e.:
var oldVal = obj[1];
obj[1] = newVal;
It is "different" because:
it has no explicit name
it accepts a parameter (or parameters)
note that the indexer parameters do not have to be integers; the can be all sorts:
Dictionary<string, decimal> lookup = ...
string employeeKey = "000006";
decimal salary = lookup[employeeKey];
This is an indexer property, a kind of property that lets your custom class participate in expressions that pass array subscripts in square brackets.
This indexer replaces an indexer property of its base class (likely, a collection), which must also have an indexer property. The getter forwards the call to the base, while the setter also calls CollectionModified, presumably to notify whomever is watching for modifications in the collection.
It is an Indexer. It works like this (No need to call any property):
yourPoints[0] = new Point3D();
Point3D point = yourPoints[0];
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.
I have a class property exposing an internal IList<> through
System.Collections.ObjectModel.ReadOnlyCollection<>
How can I pass a part of this ReadOnlyCollection<> without copying elements into a new array (I need a live view, and the target device is short on memory)? I'm targetting Compact Framework 2.0.
Try a method that returns an enumeration using yield:
IEnumerable<T> FilterCollection<T>( ReadOnlyCollection<T> input ) {
foreach ( T item in input )
if ( /* criterion is met */ )
yield return item;
}
These foreach samples are fine, though you can make them much more terse if you're using .NET 3.5 and LINQ:
return FullList.Where(i => IsItemInPartialList(i)).ToList();
You can always write a class that implements IList and forwards all calls to the original list (so it doesn't have it's own copy of the data) after translating the indexes.
You could use yield return to create a filtered list
IEnumerable<object> FilteredList()
{
foreach( object item in FullList )
{
if( IsItemInPartialList( item )
yield return item;
}
}
Depending on how you need to filter the collection, you may want to create a class that implements IList (or IEnumerable, if that works for you) but that mucks about with the indexing and access to only return the values you want. For example
class EvenList: IList
{
private IList innerList;
public EvenList(IList innerList)
{
this.innerList = innerList;
}
public object this[int index]
{
get { return innerList[2*i]; }
set { innerList[2*i] = value; }
}
// and similarly for the other IList methods
}
How do the filtered elements need to be accessed? If it's through an Iterator then maybe you could write a custom iterator that skips the elements you don't want publicly visible?
If you need to provide a Collection then you might need to write your own Collection class, which just proxies to the underlying Collection, but prevents access to the elements you don't want publicly visible.
(Disclaimer: I'm not very familiar with C#, so these are general answers. There may be more specific answers to C# that work better)