Easy creation of properties that support indexing in C#

I found your idea useful, so I extended it. This may not technically be a proper answer since I'm not sure it squarely answers your question, but I thought it might be useful to people who came here looking for property indexers.

First, I needed to be able to support get-only and set-only properties, so I made a slight variation of your code for these scenarios:

Get and Set (very minor changes):

public class IndexedProperty<TIndex, TValue>
{
    readonly Action<TIndex, TValue> SetAction;
    readonly Func<TIndex, TValue> GetFunc;

    public IndexedProperty(Func<TIndex, TValue> getFunc, Action<TIndex, TValue> setAction)
    {
        this.GetFunc = getFunc;
        this.SetAction = setAction;
    }

    public TValue this[TIndex i]
    {
        get
        {
            return GetFunc(i);
        }
        set
        {
            SetAction(i, value);
        }
    }
}

Get Only:

public class ReadOnlyIndexedProperty<TIndex, TValue>
{
    readonly Func<TIndex, TValue> GetFunc;

    public ReadOnlyIndexedProperty(Func<TIndex, TValue> getFunc)
    {
        this.GetFunc = getFunc;
    }

    public TValue this[TIndex i]
    {
        get
        {
            return GetFunc(i);
        }
    }
}

Set Only:

public class WriteOnlyIndexedProperty<TIndex, TValue>
{
    readonly Action<TIndex, TValue> SetAction;

    public WriteOnlyIndexedProperty(Action<TIndex, TValue> setAction)
    {
        this.SetAction = setAction;
    }

    public TValue this[TIndex i]
    {
        set 
        {
            SetAction(i, value);
        }
    }
}

Example

Here's a simple usage example. I inherit from Collection and create a named indexer, as Jon Skeet called it. This example is intended to be simple, not practical:

public class ExampleCollection<T> : Collection<T>
{
    public IndexedProperty<int, T> ExampleProperty
    {
        get
        {
            return new IndexedProperty<int, T>(GetIndex, SetIndex);
        }
    }

    private T GetIndex(int index)
    {
        return this[index];
    }
    private void SetIndex(int index, T value)
    {
        this[index] = value;
    }
}

ExampleCollection in the Wild

This hastily constructed unit test shows how it looks when you ExampleCollection in a project:

[TestClass]
public class IndexPropertyTests
{
    [TestMethod]
    public void IndexPropertyTest()
    {
        var MyExample = new ExampleCollection<string>();
        MyExample.Add("a");
        MyExample.Add("b");

        Assert.IsTrue(MyExample.ExampleProperty[0] == "a");
        Assert.IsTrue(MyExample.ExampleProperty[1] == "b");

        MyExample.ExampleProperty[0] = "c";

        Assert.IsTrue(MyExample.ExampleProperty[0] == "c");

    }
}

Finally, if you want to use the get-only and set-only versions, that looks like this:

    public ReadOnlyIndexedProperty<int, T> ExampleProperty
    {
        get
        {
            return new ReadOnlyIndexedProperty<int, T>(GetIndex);
        }
    }

Or:

    public WriteOnlyIndexedProperty<int, T> ExampleProperty
    {
        get
        {
            return new WriteOnlyIndexedProperty<int, T>(SetIndex);
        }
    }

In both cases, the result works the way you would expect a get-only/set-only property to behave.


Well, the simpliest is to have the property return an object which implements IList.

Remember that just because it implements IList doesn't mean it's a collection itself, just that it implements certain methods.


I think the design you've posted is the way to go, with the one difference that I would define an interface:

public interface IIndexed<IndexT, ValueT>
{
    ValueT this[IndexT i] { get; set; }
}

And for common cases, I would use the class you put in the original question (which would implement this interface).

It would be nice if the base class library provided a suitable interface for us, but it doesn't. Returning an IList here would be a perversion.