在C#中命名的索引属性?

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的最简单(就代码长度和复杂性而言)方法。当然,除非有人贴得更短更简单。