Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C#中实现嵌套的[]运算符?_C#_Oop - Fatal编程技术网

如何在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]
不是非常可读的代码,或者是我想写的代码(可能除非用矩阵运算实现)。。。