Indexed Properties in C#
C# does allow for indexed access on classes (the [ ] notation), but no built in mechanism to use the same notation on properties. What I mean is, I want to easily do this:
- var testValue = settings.ByName["testSetting"];
or
- settings.ByName["testSetting"] = "testValue";
Usually this is done by creating a class which only reason to exist is to make the property accessible through indexer. For an example of that approach please see the example on MSDN.
I don't like this approach since it forces me to create a class for every property I want use to indexes on, even though they usually are very "thin" classes.
Fortunately lambdas allow for a pretty elegant solution that does not require a subclass for every indexed property. I'll just show the final helper class and go from there:
- public class IndexedProperty<Index, Return> {
- private Func<Index, Return> m_getter;
- private Action<Index, Return> m_setter;
- public IndexedProperty(Func<Index, Return> getter, Action<Index, Return> setter) {
- m_getter = getter;
- m_setter = setter;
- }
- public Return this[Index index] {
- get { return m_getter(index); }
- set { m_setter(index, value); }
- }
- }
One simple example on how to use this class is by implementing the appropriate filtering methods as regular methods hosted within the same class that wants to provide an indexed property. In the example the SettingContainer class wants to allow a direct access to its List of Setting via the name of the setting. It would of course be possible to use Setting GetSetting(string name) but I like the Setting Option[string name] syntax better. But I guess that's just a matter of taste.
In this example the IndexedProperty will be initialized by private methods of the SettingContainer that allow for the appropriate filtering:
- public class SettingContainer {
- public SettingContainer() {
- }
- private Setting GetSettingByName(string name) {
- return m_settingz.Find(
- (s) =>
- {
- return s.Name == name;
- }
- );
- }
- private void SetSettingByName(string name, Setting setting)
- {
- var index = m_settingz.FindIndex(
- (u) =>
- {
- return u.Name == name;
- }
- );
- if (index <0) {
- // setting was not found -> append to list
- m_settingz.Add(setting);
- }
- else {
- m_settingz[index] = setting;
- }
- }
- public IList<Setting> Settingz {
- get { return m_settingz; }
- }
- public IndexedProperty<string, Setting> Option { get; private set; }
- public class Setting {
- public string Name { get; set; }
- // ...
- }
- }
Of course it is just as valid to use lambdas directly in order to initialize the IndexedProperty. In this next example we will see the use of a similar class - the IndexedGetProperty, which only hosts the possibility to allow get access via the indexed property. Please look at the code in the zip file for the implementation details of IndexedGetProperty.
Please pay special attention to the direct initialization of IndexedGetProperty via lambda.
- public class ReadonlySettingContainer {
- public ReadonlySettingContainer() {
- SettingByName = new IndexedGetProperty<string, Setting>(
- (name) =>
- {
- return m_settingz.Find(
- (s) =>
- {
- return s.Name == name;
- }
- );
- }
- );
- }
- public IList<Setting> Settingz {
- get { return m_settingz.AsReadOnly(); }
- }
- public IndexedGetProperty<string, Setting> SettingByName { get; private set; }
- public class Setting {
- public string Name { get; set; }
- }
- }
Conclusion:
In this article we have seen a helper class that allows for indexed property without the use of subclasses. Using Func and Action as initialization parameters it helps keeping the SettingContainer class to be short and cohese. The filtering methodology is right were it belongs, within the SettingContainer class itself and not capsuled away in any subclass.

This would probably do what you want, with minimal new code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication3
{
class Foo
{
Dictionary myBar = new Dictionary();
public Dictionary Bar
{
get { return myBar; }
}
public Foo()
{
myMoo = new ReadOnlyDictionary(myBar);
}
ReadOnlyDictionary myMoo;
public ReadOnlyDictionary Moo
{
get { return myMoo; }
}
public string this[string index]
{
get
{
return Bar[index];
}
}
}
public class ReadOnlyDictionary
{
Dictionary myDictionary;
public ReadOnlyDictionary(Dictionary dictionary)
{
myDictionary = dictionary;
}
public V this[K index]
{
get
{
return myDictionary[index];
}
}
}
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo();
foo.Bar["hello"] = “far”;
Console.WriteLine(foo.Bar["hello"]);
}
}
}
Comment on January 28, 2009 @ 00:30:26
Hey Koushik,
there is a subtile difference between your approach and mine. yours does indeed allow for indexed properties – but it does not allow me to use custom code to give eg the getter custom behaviour.
Thanks for your comment though.
Cheers,
Tobi
Comment on January 28, 2009 @ 11:06:20
Hi and thanks for the idea (may solve my problem).
But only one question :
In your code :
“private Func m_getter;”
What is Func ? VStudio asks me for a definition…
(same thing for Action).
Thanks and have a nice day.
Comment on November 4, 2009 @ 14:22:15
Sorry for the (stupid) question.
A “using System” solved my problem
Thanks for the tip, helps me a lot.
Comment on November 4, 2009 @ 17:30:14
Hey GuiGau,
cool, nice to hear that it worked out for you. Thanks for dropping by.
Cheers,
Tobi
Comment on November 13, 2009 @ 00:15:00