Named indexed property in C#?
一些语言(如Delphi)有一种非常方便的创建索引器的方法:不仅可以对整个类进行索引,甚至可以对单个属性进行索引,例如:
1 2 3 4 5 6 7 | 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; |
这很容易使用:
1 2 3 4 5 6 7 | var c : TMyClass; begin c = TMyClass.Create; c.MyProp[5] := 'Ala ma kota'; c.Free; end; |
号
有没有一种方法可以轻松地在C中达到同样的效果?
众所周知的解决方案是创建一个代理类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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; } } } |
但是(除此之外,这实际上解决了问题),这个解决方案主要只引入了缺点:
- 它会导致代码被很多小代理类(可能)污染。
- 提出的解决方案稍微破坏了封装(内部类访问外部类的私有成员),更好的解决方案将列表实例传递给EDOCX1的ctor,这将需要更多的代码。
- 我不建议公开内部助手类。可以通过引入额外的接口来解决这个问题,但这甚至是一个要实现的实体(测试、维护等)。
不过,还有另一种方法。它还污染了代码,但肯定比之前的代码污染小得多:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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; } } } |
号
赞成的意见:
- 没有代理类(在内存中占用空间,仅用于单一目的,在最简单的解决方案中)会破坏封装。
- 简单的解决方案,只需很少的代码即可添加另一个索引属性
欺骗:
- 每个属性都需要不同的公共接口
- 随着索引属性的增加,类实现了越来越多的接口
这是将索引属性引入C的最简单(就代码长度和复杂性而言)方法。当然,除非有人贴得更短更简单。