'Custom Named Property Indexers
Is there any possible way to make a property that uses an indexer other than one global one for the whole class? Here's the gist of what I want to do. Note that in this example, you should pretend I cannot move data
or create another Dictionary
.
class MyClass
{
protected Dictionary<string,object> data = new Dictionary<string,object>();
public object Foo[int index]
{
get {
string name = String.Format("foo{0}",index);
return data[name];
}
}
public object Bar[int index]
{
get {
string name = String.Format("bar{0}",index);
return data[name];
}
}
}
I would then be able to reference an item of the data
named foo15
or bar12
like so
MyClass myClass = new MyClass();
Console.WriteLine(myClass.Foo[15]);
Console.WriteLine(myClass.Bar[12]);
I'm aware you can do this, but this isn't what I want.
public object this[string index]
{
get {
return data[index];
}
}
Solution 1:[1]
You can do it, but it requires jumping through some hoops. C# does not support Indexed Properties natively. I learned how using this post: Easy creation of properties that support indexing in C#
First declare an IndexedProperty class:
public class IndexedProperty<TIndex, TValue>
{
Action<TIndex, TValue> setAction;
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);
}
}
}
And here's one example of using it (the referenced post contains a simpler example):
protected Dictionary<DialogResult, string> ButtonNames { get; set; }
public IndexedProperty<DialogResult, string> ButtonName
{
get
{
return new IndexedProperty<DialogResult, string>(
r =>
{
if (ButtonNames.ContainsKey(r)) return ButtonNames[r];
return r.ToString();
},
(r, val) => ButtonNames[r] = val);
}
}
Later...
tableLayoutPanel2.Controls.Add(new Button
{
Text = ButtonName[btn], DialogResult = btn,
Anchor = AnchorStyles.Right
});
And the ButtonNames can be set from outside the class like:
msgbox.ButtonName[DialogResult.Cancel] = "Don't Do The Thing";
Solution 2:[2]
You'll need to create a new type, have Foo
return an instance of that type, give that other type an indexer, and have that indexer do whatever you want it to do.
Solution 3:[3]
A class in C# cannot have named indexers but can have multiple indexers with different signature. A possible approach is using different indexer interfaces and let your "named indexer" just return the class itself casted to the proper "interface".
Your example would become:
class MyClass: MyClass.IFooIndexer, MyClass.IBarIndexer
{
public interface IFooIndexer { object this[int index] { get; } }
public interface IBarIndexer { object this[int index] { get; } }
protected Dictionary<string, object> data = new Dictionary<string, object>();
//implementing Interfaces
object IFooIndexer.this[int index] {
get => data[$"foo{index}"];
}
object IBarIndexer.this[int index] {
get => data[$"bar{index}"];
}
// these are your "named" indexers
public IFooIndexer Foo => (IFooIndexer)this;
public IBarIndexer Bar => (IBarIndexer)this;
//add some data to test with
public MyClass()
{
data.Add("foo15", "<foo 15 value>");
data.Add("bar12", "<bar 12 value>");
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Community |
Solution 2 | Servy |
Solution 3 | Merilix2 |