命名属性包装器上的C#Indexer

时间:2011-04-25 00:25:43

标签: c#

我有遗留的代码,我试图淘汰,我无法改变。它是一个基于列的数据存储类,可以根据列的名称编制索引。像这样:

StorageClassName scn = new StorageClassName("Property_Name",new double[]{1,2,3});
double[] d = scn["Property_Name"];

我正在尝试创建某种包装类,它允许我实现接口/类继承。

BetterStorageClassName bscn = scn;
double[] d = bscn.PropertyName;

完成此包装类的最佳方法是什么?它不一定需要隐含。

编辑:我放弃了这个问题的主要部分。我在第一部分得到的答案虽然很好。我将如何以其他方式进行转换?

 double[] d = bscn["PropertyName"];

我假设这在某种程度上使用了反射。

3 个答案:

答案 0 :(得分:2)

如果您有一个包含字符串索引器的类,并且您想将其转换为属性,则可以使用dynamic执行此操作:

class StorageClassName : Dictionary<string, double[]>
{}

class DynamicStorageClassName : DynamicObject
{
    private readonly StorageClassName m_storageClassName;

    public DynamicStorageClassName(StorageClassName storageClassName)
    {
        m_storageClassName = storageClassName;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (m_storageClassName.ContainsKey(binder.Name))
        {
            result = m_storageClassName[binder.Name];
            return true;
        }

        return base.TryGetMember(binder, out result);
    }
}

用法:

var scn = new StorageClassName { { "PropertyName", new double[] { 1, 2, 3 } } };
dynamic dscn = new DynamicStorageClassName(scn);
Console.WriteLine(dscn.PropertyName[1]);

请注意,使用dynamic会对性能造成一定的损失,如果属性集不会改变,则应该像其他人建议的那样使用普通属性。

另一方面,如果您有一个具有普通属性的类并希望将其转换为使用索引器,则可以使用反射:

class StaticStorageClassName
{
    public double[] PropertyName { get; set; }

    public StaticStorageClassName()
    {
        PropertyName = new double[] { 1, 2, 3 };
    }
}

class ReverseStorageClassName
{
    private readonly StaticStorageClassName m_staticStorageClassName;

    public ReverseStorageClassName(StaticStorageClassName staticStorageClassName)
    {
        m_staticStorageClassName = staticStorageClassName;
    }

    public double[] this[string name]
    {
        get
        {
            var propertyInfo = typeof(StaticStorageClassName).GetProperty(name);
            if (propertyInfo == null)
                throw new ArgumentException();

            return (double[])propertyInfo.GetValue(m_staticStorageClassName, null);
        }
    }
}

用法:

var sscn = new StaticStorageClassName();
var rscn = new ReverseStorageClassName(sscn);
Console.WriteLine(rscn["PropertyName"][2]);

如果各种属性具有不同的类型,则必须使索引器的返回类型为objectdynamic

请注意,如果使用StaticStorageClassName实现DynamicObject,则无法使用反射。

答案 1 :(得分:1)

对于给出的示例,我认为它的实现方式如下:

public double[] PropertyName
{
    get { return wrapped["Property_Name"]; }
    set { wrapped["Property_Name"] = value; }
}

您是否试图避免编写所有这些包装器?或者进行类型转换?

答案 2 :(得分:1)

从您的问题我想你想要完整的命名属性而不是基于字符串的键。在这种情况下,您只需提供访问属性:

class BetterStorageClassName : StorageClassName 
{
    public double[] PropertyName
    {
        get { return this["Property_Name"]; }
        set { this["Property_Name"] = value; }
    }
}

然而,该方法有几点需要注意:

  • 这意味着属性是固定的,并没有真正改变,因为否则你最终会不断修改你的包装。
  • 无法在运行时动态定义属性。
  • 您必须为每组属性设置一个包装类。