Reputation: 25927
A few languages - like Delphi - has a very convenient way of creating indexers: not only the whole class, but even single properties can be indexed, for instance:
type TMyClass = class(TObject)
protected
function GetMyProp(index : integer) : string;
procedure SetMyProp(index : integer; value : string);
public
property MyProp[index : integer] : string read GetMyProp write SetMyProp;
end;
This can be used easily:
var c : TMyClass;
begin
c = TMyClass.Create;
c.MyProp[5] := 'Ala ma kota';
c.Free;
end;
Is there a way to achieve the same effect in C# easily?
Upvotes: 5
Views: 5349
Reputation: 749
This is based on H B's comment, but expanded a little and as a code block (making copying easier):
public interface IIndexedProperty<TValue> : IIndexedProperty<int, TValue> {}
public interface IReadOnlyIndexedProperty<out TValue> : IReadOnlyIndexedProperty<int, TValue> {}
public interface IIndexedProperty<in TIndex, TValue>
{
TValue this[TIndex index] { get; set; }
}
public interface IReadOnlyIndexedProperty<in TIndex, out TValue>
{
TValue this[TIndex index] { get; }
}
This uses covarients from C# 9.0, so if you are using an older version, strip out the in
and out
statements.
Pros:
Most common indexed properties use a simple int
index, so this allows for a simpler class / property signature if the index only needs to be an int
, but it also allows for non int
indexes.
Also provides both a read/write implementation and a read-only implementation based on your needs.
Caveat I found after trying to use this:
The shortcut for int
index only class signature. It apparently still needs the full signature for the property.
IE:
public MyClass : IIndexedProperty<string>
{
public IIndexedProperty<string> MyString => this;
string IIndexedPropety<int, string>.this[int index] { get; set; }
}
Upvotes: 0
Reputation: 25927
The well-known solution is to create a proxy class:
public class MyClass
{
public class MyPropProxy
{
private MyClass c;
// ctor etc.
public string this[int index]
{
get
{
return c.list[index];
}
set
{
c.list[index] = value;
}
}
}
private List<string> list;
private MyPropProxy myPropProxy;
// ctor etc.
public MyPropProxy MyProp
{
get
{
return myPropProxy;
}
}
}
But (with exception, that this actually solves the problem), this solution introduces mostly only cons:
MyPropProxy
's ctor, what would require even more code. There's another way, though. It also pollutes the code a little, but surely a lot less, than the previous one:
public interface IMyProp
{
string this[int index] { get; }
}
public class MyClass : IMyProp
{
private List<string> list;
string IMyProp.this[int index]
{
get
{
return list[index];
}
set
{
list[index] = value;
}
}
// ctor etc.
public IMyProp MyProp
{
get
{
return this;
}
}
}
Pros:
Cons:
This is the simplest (in terms of code length and complexity) way of introducing indexed properties to C#. Unless someone posts even shorter and simpler one, of course.
Upvotes: 14