Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.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# 递归,can';不能使嵌套的自对象为空,为什么会这样?_C#_.net_Recursion - Fatal编程技术网

C# 递归,can';不能使嵌套的自对象为空,为什么会这样?

C# 递归,can';不能使嵌套的自对象为空,为什么会这样?,c#,.net,recursion,C#,.net,Recursion,我试图在递归代码中更新self对象的列表,但它没有这样做,但是当通过更改值来更新对象时,效果很好 名称空间测试 { 班级计划 { 静态void Main(字符串[]参数) { 节点main=新节点(); main.Sequence=“1”; main.Id=1; main.ChildNodes.Add(新节点() { Sequence=“1.1”, Id=2 }); main.ChildNodes.Add(新节点() { Sequence=“1.2”, Id=3 }); main.ChildN

我试图在递归代码中更新self对象的列表,但它没有这样做,但是当通过更改值来更新对象时,效果很好

名称空间测试
{
班级计划
{
静态void Main(字符串[]参数)
{
节点main=新节点();
main.Sequence=“1”;
main.Id=1;
main.ChildNodes.Add(新节点()
{
Sequence=“1.1”,
Id=2
});
main.ChildNodes.Add(新节点()
{
Sequence=“1.2”,
Id=3
});
main.ChildNodes.Add(新节点()
{
Sequence=“1.3”,
Id=4
});
Console.WriteLine(“之前:”);
打印节点(主);
Console.WriteLine();
MakeNull(main);
控制台。WriteLine(“在:”)之后;
打印节点(主);
void MakeNull(节点)
{
foreach(节点中的变量Child.ChildNodes)
{
MakeNull(Child);
}
node.ChildNodes.RemoveAll(p=>p==null);
如果(node.ChildNodes.Count==0)
{
node.Id=5;//这正在工作
node=null;//这不是,为什么?
}
}
Console.ReadLine();
}
静态void打印节点(节点)
{
Console.WriteLine(“Id:+node.Id+”序列:+node.Sequence);
对于(int i=0;i

为什么不将整个对象设为null?

因为在方法MakeNull(Node Node)中,Node成为该范围内的一个引用,从调用函数中保存“main”对象。在函数中将node设置为null,只有在该方法中将节点引用设置为null时才有效。对“main”的引用丢失(被null覆盖)

这并不意味着MakeNull(Node-Node)方法之外的“main”变为null

设置Id确实有效,因为您在用null覆盖节点引用之前设置了Id。此时,节点仍然引用“main”,我们可以获得对Id的setter的引用,然后设置其值

如果要使列表中的项为null,必须执行如下操作:main[i]=null

其他人指出,使用ref关键字应该可以做到这一点,但这仅适用于MakeNull(main)。不适用于子项。在您所做的工作中,您可能希望看到一个“null”子项列表(例如,调用ChildItem[1],然后希望看到“null”)。但事实并非如此

请参阅下面的代码片段,以了解将发生的情况:

            List<Bla> a = new List<Bla>();

            a.Add(new Bla());
            a.Add(new Bla());
            a.Add(new Bla());

            void MakeNull(ref Bla a) { a = null; }

            var a1 = a[1];

            MakeNull(ref a1);
            // MakeNull(ref a[1]);              // not allowed by compiler
            // MakeNull(ref a.ElementAt(1));    // not allowed by compiler

            Console.WriteLine(a1); // prints nothing (null)
            Console.WriteLine(a[1]); // prints "Core.App.Bla"

List a=新列表();
a、 添加(新Bla());
a、 添加(新Bla());
a、 添加(新Bla());
void MakeNull(ref Bla a){a=null;}
var a1=a[1];
MakeNull(参考a1);
//MakeNull(参考文献a[1]);//编译器不允许
//MakeNull(参考a.ElementAt(1));//编译器不允许
控制台写入线(a1);//不打印任何内容(空)
Console.WriteLine(a[1]);//打印“Core.App.Bla”
您可以通过使用lambda操作来解决此问题,该操作引用集合上的实际索引器方法或另一个setter方法

            void MakeNullAction(Action<Bla> setter) { setter(null); }

            MakeNullAction((value) => a[1] = value);

            Console.WriteLine(a[1]); // prints nothing (null)

void MakeNullAction(操作设置器){setter(null);}
MakeNullAction((值)=>a[1]=值);
Console.WriteLine(a[1]);//不打印任何内容(空)

将函数参数声明为引用类型时,该值将通过引用传递给函数。这意味着,当您将一个方法参数声明为type
Node
时,您将获得一个指针的副本,该指针指向传递到方法中的同一内存位置,而实际上并不是传递对象本身

        void MakeNull(Node node) // <-- This is a new variable that points to the same memory location as the variable that was passed in
        {
            foreach (var Child in node.ChildNodes)
            {
                MakeNull(Child);
            }
            node.ChildNodes.RemoveAll(p => p == null);
            if (node.ChildNodes.Count == 0)
            {
                node.Id = 5;
                node = null;
            }
        }
void MakeNull(Node Node)//p==null);
如果(node.ChildNodes.Count==0)
{
node.Id=5;
node=null;
}
}
变量
节点
的范围仅限于方法,因为方法参数是声明它的地方。当您在方法中将其设置为
null
时,您只是在销毁指向方法内部
节点
内存位置的指针,但传递到方法中的指针保持不变,因为它在调用方法时已被复制

为什么不能使整个对象为空

简而言之,因为对象不能设置为null。只能使用对象指针(变量)。您正在处理两个类型为
Node
的独立对象指针,一个在方法内部,一个在方法外部


将方法内部的
节点
变量设置为
null
只会破坏在方法开头创建的指针。当您拥有对内存位置的引用,并将其
Id
属性更新为
5
时,您使用的是对象本身,而不是对象指针。

要了解发生了什么,必须知道类是引用类型。即,此类型的变量包含
null
或对对象的引用。它们不包含对象本身或存储在此对象中的值

这与
int
等值类型不同。这种类型的变量实际上是c
void MakeNull(ref Node node)
{
    ...
    node = null;
    ...
}
MakeNull(ref main);
MakeNull(ref Child);
MakeNull(ref main);