如何在C#中实现嵌套的[]运算符?
考虑一类嵌套数组,每个元素可以是数组或数字:如何在C#中实现嵌套的[]运算符?,c#,oop,C#,Oop,考虑一类嵌套数组,每个元素可以是数组或数字: [[1, 2, [3, 4, [5]], [6, 7]], 8] 下面是我为它实现[]操作符的尝试 类MyArray{ 列出要素; int值; 公共对象此[int索引]{ 得到{ 如果(elements.Count>0){ 返回元素; }否则{ 返回值; } } } } 因此,我们的目标是按如下方式使用它: MyArray arr=newmyarray(); ... 在这里对数组执行一些操作。。。 int num=arr[3][5][1]; 如
[[1, 2, [3, 4, [5]], [6, 7]], 8]
下面是我为它实现[]操作符的尝试
类MyArray{
列出要素;
int值;
公共对象此[int索引]{
得到{
如果(elements.Count>0){
返回元素;
}否则{
返回值;
}
}
}
}
因此,我们的目标是按如下方式使用它:
MyArray arr=newmyarray();
... 在这里对数组执行一些操作。。。
int num=arr[3][5][1];
如果访问的是“分支”,而不是“叶”(比如,arr[3][5][1]有多个元素),那么让我们只返回0、无穷大或对我们来说合适的任何整数
但是,很明显,这种嵌套运算符不适用于我的情况,因为运算符的结果是一个对象,而不是MyArray实例
现在,我看到了唯一的解决方案:将转换运算符定义为int,并使[]运算符始终只返回一个元素(如果这里没有异常,那么它将是MyArray)。但是还有别的办法吗?也许,使用类似IList的接口可以有所帮助?或者也许有一种方法可以为一个方法定义多种可能的返回类型?(但到目前为止,我在谷歌上搜索到这是不可能的,而且C#中没有任何一种类型)您的操作符应该返回
MyArray
。此外,您应该实现MyArray
到int
的隐式转换运算符:
class MyArray {
List<MyArray> elements;
int value;
public MyArray this[int index] {
get {
return elements[index];
}
}
public static implicit operator int(MyArray d) {
return d.value;
}
}
类MyArray{
列出要素;
int值;
公共MyArray此[int索引]{
得到{
返回元素[索引];
}
}
公共静态隐式运算符int(MyArray d){
返回d值;
}
}
问题在于MyArray
的结构不是同质的:编译器无法知道它将从[]
运算符中获得什么,但您必须指定确切的类型
另一种选择是在返回中使用
动态
,但它的使用会带来严重的性能损失。您所表示的是逻辑“树”类型的数据结构,您只需要使用索引器访问元素(如果您在编译时倾向于了解树的结构,这很好)
通常对于基于树的数据结构,复合模式是适用的。您有一个定义节点的接口,然后有两种类型的类来实现它;一个用于叶节点,一个用于父节点。然后,节点接口有一些其他节点(或集合)(可以是实现,如果是叶节点,则可以是空集合)
这里是一个不使用接口的简单实现;它没有那么强大(它更多地依赖于惯例来告诉你发生了什么),但概念是一样的:
public class Node
{
private List<Node> children = new List<Node>();
/// <summary>
/// This will have a non-null value if it's a leaf. It will be null if it's not a leaf.
/// </summary>
public int? Value { get; set; }
public Node this[int index]
{
get
{
if (children.Count == 0)
{
throw new ArgumentException("This node has no children");
}
if (children.Count > index)
{
throw new ArgumentException("This node doesn't have that many children");
}
return children[index];
}
}
}
公共类节点
{
私有列表子项=新列表();
///
///如果它是一个叶子,它将有一个非null值。如果它不是叶子,它将是null。
///
公共int?值{get;set;}
公共节点此[int索引]
{
得到
{
如果(children.Count==0)
{
抛出新ArgumentException(“此节点没有子节点”);
}
如果(children.Count>索引)
{
抛出新ArgumentException(“此节点没有那么多子节点”);
}
返回子项[索引];
}
}
}
Hmm,也许隐式操作符应该朝相反的方向去?(编辑)任何int
都是一个MyArray
,但并非所有MyArray
都只代表一个整数。@demeshchuk是的,你说得对,我刚刚修复了它。使用dynamic
可能是另一种可能性(这也是在上一次编辑中)。好吧,我的目标不是每次我想要获得实际值时都使用值获取程序(这应该是一个JSON解析器)。此外,我不会使用额外的ArgumentException实例,因为默认实例(在数组溢出的情况下)已经具有足够的声明性。@demeshchuk我认为最终结果最好使用value属性。它使代码更清晰,更容易为其他人使用,即使需要更多的代码。至于参数异常,这是你如何处理它们的选择。旁注:如果你真的希望在人类读/写的代码(不是自动生成的代码)中使用它,我会尝试考虑其他方法。我认为arr[3][5][1]
不是非常可读的代码,或者是我想写的代码(可能除非用矩阵运算实现)。。。