c#命名属性包装上的索引器
本文关键字:索引 包装 属性 | 更新日期: 2023-09-27 17:52:38
我有遗留代码,我试图淘汰,我不能改变。它是一个基于列的数据存储类,可以根据列的名称对其进行索引。像这样:
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"];
我假设这在某种程度上使用了反射
如果你有一个带有字符串indexer的类并且你想把它转换成属性,你可以使用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
会付出一些性能损失,如果属性集不会改变,您可能应该像其他人建议的那样使用普通属性。
另一方面,如果您有一个具有普通属性的类,并希望将其转换为使用indexer,则可以使用反射:
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]);
如果不同的属性具有不同的类型,则必须将索引器的返回类型设置为object
或dynamic
。
注意,如果使用DynamicObject
实现StaticStorageClassName
,则使用反射将不起作用。
对于给出的示例,我想象它是这样实现的:
public double[] PropertyName
{
get { return wrapped["Property_Name"]; }
set { wrapped["Property_Name"] = value; }
}
您是否试图避免编写所有这些包装?或者进行类型转换?
从你的问题,我猜你想有完整的命名属性,而不是基于字符串的键。在这种情况下,您只需为访问提供属性:
class BetterStorageClassName : StorageClassName
{
public double[] PropertyName
{
get { return this["Property_Name"]; }
set { this["Property_Name"] = value; }
}
}
但是这个方法有几个注意事项:
- 这意味着属性是固定的,不会真正改变,否则你最终会不断修改包装器。
- 属性不能在运行时动态定义。
- 你必须有一个包装类的每一组属性。